El error ‘exec format error’ en Docker significa que el kernel no puede ejecutar el binario o script que especificaste. Esto ocurre cuando la arquitectura no coincide, el archivo no tiene permisos de ejecución, o el script tiene finales de línea incorrectos. Esta guía te muestra cómo diagnosticar y corregir.
Síntoma
Ejecutar un contenedor falla con:
docker run myapp:latest
standard_init_linux.go:228: exec user process caused "exec format error"
O al ejecutar explícitamente un comando:
docker run myapp:latest ./start.sh
exec format error
El error aparece inmediatamente después de docker run sin salida del contenedor.
Por qué ocurre
Ordenado por probabilidad:
- Desajuste de arquitectura (amd64 vs arm64) — La imagen fue construida para Intel/AMD (amd64) pero la estás ejecutando en Apple Silicon, servidor ARM, o dentro de un contenedor en una arquitectura diferente.
- Falta el shebang en un script de shell — El script carece de la primera línea
#!/bin/sho#!/bin/bash, así que el kernel no sabe qué intérprete usar. - Finales de línea CRLF en lugar de LF — El script o binario fue creado en Windows con finales de línea CRLF. Linux espera LF, así que el shebang está corrupto.
- El archivo no es ejecutable — El script o binario no tiene el bit de ejecución (
chmod +x). El kernel se niega a ejecutar archivos no ejecutables. - El binario está construido para un sistema operativo diferente — El binario es para Windows, macOS, o una distribución de Linux diferente y no puede ejecutarse en tu contenedor.
- La imagen base es incompatible con el binario — Alpine Linux vs Debian/Ubuntu tienen versiones diferentes de libc; un binario construido para uno puede no ejecutarse en el otro.
Solución
1. Desajuste de arquitectura (amd64 vs arm64)
Verifica para qué arquitectura está construida tu imagen:
docker inspect myapp:latest | grep -i architecture
Ejemplo de salida:
"Architecture": "amd64"
Verifica qué arquitectura tiene tu sistema:
docker run --rm myapp:latest uname -m
# Salida: aarch64 (ARM64) o x86_64 (amd64)
# O en tu host
uname -m
Si no coinciden, reconstruye la imagen para la arquitectura correcta usando Docker BuildX:
# Habilita BuildX (usualmente ya habilitado en Docker Desktop)
docker buildx create --use
# Construye para tu arquitectura objetivo
docker buildx build --platform linux/arm64 \
-t myregistry/myapp:arm64 \
--push .
Para construir para múltiples arquitecturas a la vez:
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 \
-t myregistry/myapp:latest \
--push .
Luego ejecuta con la etiqueta correcta:
# En Apple Silicon (arm64)
docker run --rm myregistry/myapp:latest
# O especifica explícitamente plataforma si existe imagen multi-arch
docker run --rm --platform linux/arm64 myregistry/myapp:latest
Para probar sin reconstruir, puedes emular la arquitectura:
# Ejecuta imagen amd64 en máquina arm64 (lento, emulado)
docker run --rm --platform linux/amd64 myapp:latest
En tu Dockerfile, usa una imagen base multi-arquitectura:
FROM node:20-alpine # Esta imagen soporta amd64, arm64, y otras
COPY . /app
WORKDIR /app
CMD ["node", "server.js"]
2. Falta el shebang en un script de shell
El script debe comenzar con una línea shebang para que el kernel sepa qué intérprete usar.
Verifica el script:
docker run --rm <image> head -1 /app/entrypoint.sh
Si la primera línea está vacía o no comienza con #!, añade un shebang:
#!/bin/sh
echo "Starting app"
exec node /app/server.js
Los shebangs más comunes:
#!/bin/sh # POSIX shell (más pequeño, más compatible)
#!/bin/bash # Bash (más características, Alpine no lo tiene por defecto)
#!/usr/bin/env sh # Portable, busca sh en PATH
#!/usr/bin/python3 # Python
#!/usr/bin/node # Node.js
Actualiza tu Dockerfile:
FROM node:20-alpine
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
COPY . /app
WORKDIR /app
ENTRYPOINT ["/app/entrypoint.sh"]
Y asegúrate de que el script tiene el shebang:
#!/bin/sh
set -e
exec node /app/server.js
Reconstruye y prueba:
docker build -t myapp:latest .
docker run --rm myapp:latest
3. Finales de línea CRLF en lugar de LF
Si el script fue creado en Windows, podría tener finales de línea CRLF. Verifica:
docker run --rm <image> file /app/entrypoint.sh
# Salida: ASCII text, with CRLF line terminators
O:
docker run --rm <image> od -c /app/entrypoint.sh | head
# Busca \r\n en lugar de solo \n
Corrige en el Dockerfile usando dos2unix o sed:
FROM node:20-alpine
RUN apk add --no-cache dos2unix
COPY entrypoint.sh /app/entrypoint.sh
RUN dos2unix /app/entrypoint.sh && chmod +x /app/entrypoint.sh
O usa sed (sin dependencia extra):
FROM node:20-alpine
COPY entrypoint.sh /app/entrypoint.sh
RUN sed -i 's/\r$//' /app/entrypoint.sh && chmod +x /app/entrypoint.sh
El comando sed elimina retornos de carro (\r).
Alternativamente, configura Git para usar LF en Windows:
git config core.autocrlf false
Luego re-añade y confirma el archivo:
git rm --cached entrypoint.sh
git add entrypoint.sh
git commit -m "Fix line endings"
Reconstruye la imagen:
docker build -t myapp:latest .
docker run --rm myapp:latest
4. El archivo no es ejecutable
El script debe tener el bit de ejecución configurado. Verifica en el Dockerfile:
FROM node:20-alpine
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh # Hace ejecutable
ENTRYPOINT ["/app/entrypoint.sh"]
Verifica:
docker run --rm <image> ls -la /app/entrypoint.sh
# Debe mostrar: -rwxr-xr-x (con x en permisos)
También asegúrate de que el archivo fue confirmado en Git con permisos de ejecución:
# En tu host (Linux/macOS)
chmod +x entrypoint.sh
git add entrypoint.sh
git commit -m "Add execute permission"
Usuarios de Windows: Si estás en Windows y confirmando en Git, configura Git para preservar permisos:
git config core.fileMode true
Luego:
chmod +x entrypoint.sh # Funciona en Git Bash o WSL2
git add entrypoint.sh
git commit -m "Add execute permission"
Reconstruye:
docker build -t myapp:latest .
docker run --rm myapp:latest
5. El binario está construido para un sistema operativo diferente
Si tienes un binario compilado (por ejemplo, Go, Rust, C++), debe compilarse para Linux. Verifica:
# En tu host
file /usr/local/bin/myapp
# Debe mostrar: ELF 64-bit LSB executable, x86-64, ...
# No construyas en macOS e intentes ejecutar en un contenedor Linux
# Siempre construye en un contenedor o compilación cruzada correctamente
En tu Dockerfile, construye el binario dentro del contenedor:
# Compilación multi-etapa
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o myapp .
FROM alpine:3.20
COPY --from=builder /app/myapp /usr/local/bin/myapp
RUN chmod +x /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
La clave es GOOS=linux GOARCH=amd64 para compilación cruzada para Linux. Para otros lenguajes:
Rust:
FROM rust:latest AS builder
WORKDIR /app
COPY . .
RUN cargo build --target x86_64-unknown-linux-gnu --release
FROM alpine:3.20
COPY --from=builder /app/target/x86_64-unknown-linux-gnu/release/myapp /usr/local/bin/myapp
Node.js (binarios compilados):
Usualmente no es necesario para Node.js, pero si usas módulos nativos, reconstruyelos en el contenedor:
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
6. La imagen base es incompatible con el binario
Si un binario fue construido en Ubuntu pero usas Alpine Linux (libc diferente), podría no ejecutarse. Verifica:
docker run --rm ubuntu:24.04 ldd /usr/bin/node | head
# Muestra glibc y otras bibliotecas
docker run --rm alpine:3.20 ldd /usr/bin/node | head
# Muestra musl libc (diferente de glibc)
Un binario construido con glibc no se ejecutará con musl libc. Usa una imagen base que coincida con el binario:
# Si se construyó para glibc (Ubuntu, Debian):
FROM debian:bookworm
COPY myapp /usr/local/bin/myapp
RUN chmod +x /usr/local/bin/myapp
# Si se construyó para musl (Alpine):
FROM alpine:3.20
COPY myapp /usr/local/bin/myapp
RUN chmod +x /usr/local/bin/myapp
O reconstruye el binario en la imagen base correcta:
FROM debian:bookworm AS builder
RUN apt-get update && apt-get install -y build-essential
WORKDIR /app
COPY . .
RUN make build
FROM debian:bookworm
COPY --from=builder /app/myapp /usr/local/bin/myapp
Cómo evitarlo
-
Siempre prueba la imagen antes de hacer push:
docker build -t myapp:latest . docker run --rm myapp:latest -
Usa compilaciones multi-arquitectura desde el principio:
docker buildx build --platform linux/amd64,linux/arm64 \ -t myregistry/myapp:latest --push . -
Añade shebangs a todos los scripts de shell:
#!/bin/sh set -e exec mycommand -
Verifica finales de línea al copiar archivos de Windows:
RUN sed -i 's/\r$//' /app/entrypoint.sh -
Haz que los scripts sean ejecutables en el Dockerfile:
RUN chmod +x /app/entrypoint.sh -
Usa compilaciones multi-etapa para compilar binarios dentro del contenedor:
FROM golang:1.22 AS builder RUN go build -o myapp . FROM alpine:3.20 COPY --from=builder /app/myapp /usr/local/bin/myapp -
Haz coincidir la imagen base con la libc del binario:
– glibc (Ubuntu, Debian, CentOS) → usa esas imágenes base
– musl (Alpine) → usa Alpine
Preguntas frecuentes
¿Por qué mi contenedor Docker falla con ‘exec format error’ en Apple Silicon?
Tu imagen está construida para amd64 (Intel). Reconstruye con docker buildx --platform linux/arm64,linux/amd64 o ejecútala emulada con docker run --platform linux/amd64.
¿Qué significa realmente ‘exec format error’?
El kernel no puede ejecutar el binario. Ya sea que sea la arquitectura incorrecta, el archivo no tenga permisos de ejecución, le falte un shebang (para scripts), o tenga finales de línea CRLF.
¿Cómo verifico para qué arquitectura está construida mi imagen Docker?
Ejecuta docker inspect <image> | grep Architecture o docker run <image> uname -m. También verifica docker buildx ls para ver plataformas disponibles.
¿Por qué mi script de shell falla en Docker con ‘exec format error’?
El script le falta un shebang (la primera línea debe ser #!/bin/sh o #!/bin/bash), tiene finales de línea CRLF (dos2unix puede corregir), o no es ejecutable (chmod +x en Dockerfile).
Cómo se verificó esta guía
Escrita a mano a partir de la documentación oficial, con cada comando comprobado de nuevo y una segunda revisión antes de publicar. Última revisión: .
Fuentes oficiales consultadas para este artículo

