Skip to content

Fix: Docker exec format error

FixDevs ·

Quick Answer

How to fix Docker exec format error caused by architecture mismatch (ARM vs x86), missing shebang line, wrong entrypoint, and multi-platform build issues.

The Error

You run a Docker container and get:

exec /usr/local/bin/docker-entrypoint.sh: exec format error

Or variations:

standard_init_linux.go:228: exec user process caused: exec format error
exec /app/start.sh: exec format error
exec /usr/bin/python3: exec format error

The container starts but immediately exits with this error. Docker cannot execute the entrypoint or command because the binary format is incompatible with the container’s architecture or the script is malformed.

Why This Happens

Two main causes:

  1. Architecture mismatch. The image was built for a different CPU architecture. An image built for linux/amd64 (Intel/AMD) cannot run on linux/arm64 (Apple Silicon, AWS Graviton) and vice versa.

  2. Missing or wrong shebang line. A shell script used as the entrypoint does not have a proper #!/bin/bash or #!/bin/sh line at the top, so the kernel does not know how to execute it.

Less common causes:

  • Windows line endings in scripts. \r\n line endings in shell scripts cause the shebang interpreter to not be found.
  • Binary compiled for wrong OS. A macOS or Windows binary inside a Linux container.
  • Corrupted binary. The executable file is damaged.

Fix 1: Fix Architecture Mismatch

Check the image’s architecture:

docker inspect --format='{{.Architecture}}' my-image

Check your host’s architecture:

uname -m
# x86_64 = amd64
# aarch64 = arm64

Common mismatch: Building on an Apple Silicon Mac (arm64) and deploying to an x86_64 server, or vice versa.

Fix: Build for the target architecture:

# Build for amd64 (Intel/AMD servers)
docker build --platform linux/amd64 -t my-app .

# Build for arm64 (Apple Silicon, AWS Graviton)
docker build --platform linux/arm64 -t my-app .

Fix: Build multi-platform images:

# Create a builder that supports multiple platforms
docker buildx create --use

# Build for both architectures
docker buildx build --platform linux/amd64,linux/arm64 -t my-app --push .

This creates a manifest that includes images for both architectures. Docker automatically pulls the correct one.

Pro Tip: Always use --platform linux/amd64 in CI/CD pipelines that deploy to x86_64 servers, even if the CI runner is ARM-based. This prevents architecture mismatch surprises in production.

Fix 2: Add the Shebang Line

Shell scripts must start with a shebang line that tells the kernel which interpreter to use:

Broken — missing shebang:

# start.sh
echo "Starting app..."
exec python3 app.py

Fixed:

#!/bin/bash
echo "Starting app..."
exec python3 app.py

Or for maximum portability:

#!/bin/sh
echo "Starting app..."
exec python3 app.py

In Alpine-based images, use /bin/sh:

Alpine uses ash (BusyBox), not bash. If your script starts with #!/bin/bash but the image does not have bash:

exec /app/start.sh: exec format error

Fix: Use #!/bin/sh or install bash:

# Option 1: Use sh
# In start.sh: #!/bin/sh

# Option 2: Install bash
RUN apk add --no-cache bash

Fix 3: Fix Windows Line Endings (CRLF)

If you develop on Windows, scripts might have \r\n (CRLF) line endings. The kernel reads the shebang as #!/bin/bash\r and tries to find an interpreter called bash\r — which does not exist.

Fix: Convert line endings in the Dockerfile:

COPY start.sh /app/start.sh
RUN sed -i 's/\r$//' /app/start.sh && chmod +x /app/start.sh

Fix: Convert before building:

# Linux/macOS
sed -i 's/\r$//' start.sh

# Or using dos2unix
dos2unix start.sh

Fix: Use .gitattributes to prevent CRLF in the repo:

*.sh text eol=lf
Dockerfile text eol=lf

Common Mistake: Building Docker images on Windows without configuring line endings. Git on Windows converts \n to \r\n by default (core.autocrlf=true). This silently corrupts shell scripts. Always set eol=lf in .gitattributes for scripts and Dockerfiles.

Fix 4: Fix the Entrypoint in Dockerfile

A wrong entrypoint format can cause exec format error:

Broken — shell form without shebang:

COPY app.py /app/
ENTRYPOINT python3 /app/app.py

If Docker uses exec form internally and python3 is not found in the expected location, you get the error.

Fixed — exec form (preferred):

ENTRYPOINT ["python3", "/app/app.py"]

Fixed — shell form with explicit shell:

ENTRYPOINT ["/bin/sh", "-c", "python3 /app/app.py"]

For custom scripts:

COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
ENTRYPOINT ["/app/start.sh"]

Make sure start.sh has the shebang line and correct line endings.

Fix 5: Fix Docker Compose Platform

Specify the platform in docker-compose.yml:

services:
  app:
    image: my-app:latest
    platform: linux/amd64

Or build with the platform:

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      platforms:
        - linux/amd64

This is especially important on Apple Silicon Macs where Docker defaults to linux/arm64, but many images only support linux/amd64.

Fix 6: Fix Python/Node Binary Issues

If the exec format error points to a language runtime binary:

exec /usr/bin/python3: exec format error

The base image was built for a different architecture.

Fix: Use the correct base image:

# This automatically picks the right architecture:
FROM python:3.12-slim

# Or explicitly specify:
FROM --platform=linux/amd64 python:3.12-slim

Fix: Check available architectures for the image:

docker manifest inspect python:3.12-slim | grep architecture

For Docker daemon issues that prevent containers from starting at all, see Fix: Docker daemon is not running.

Fix 7: Fix Compiled Binaries

If you copy a pre-compiled binary into the container, it must match the container’s architecture:

Broken:

# Binary compiled on macOS ARM
COPY ./my-app /app/my-app
ENTRYPOINT ["/app/my-app"]

Fixed — compile inside the container:

FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o my-app

FROM alpine:3.19
COPY --from=builder /app/my-app /app/my-app
ENTRYPOINT ["/app/my-app"]

For Rust:

FROM rust:1.77 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM alpine:3.19
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/my-app /app/my-app
ENTRYPOINT ["/app/my-app"]

Always compile inside the Docker build stage to ensure architecture compatibility.

Fix 8: Debug the Error

Check the file type:

docker run --entrypoint file my-image /app/start.sh
# Should show: Bourne-Again shell script, ASCII text executable
# If it shows: data — the file is corrupted or has wrong format

Check the binary architecture:

docker run --entrypoint file my-image /usr/bin/python3
# Should show: ELF 64-bit LSB executable, x86-64
# If it shows: ELF 64-bit LSB executable, ARM aarch64 — architecture mismatch

Check for missing dependencies:

docker run --entrypoint ldd my-image /app/my-app
# Shows dynamic library dependencies
# "not found" entries indicate missing libraries

If the error is about image pulling rather than execution, see Fix: Docker image not found. For container permission issues, see Fix: Docker volume permission denied.

Still Not Working?

Check for QEMU emulation. Docker Desktop on Mac and Windows uses QEMU to run images for different architectures. QEMU is slower and can fail with complex binaries. If possible, use native architecture images.

Check for static vs dynamic linking. Dynamically linked binaries need the correct shared libraries. Alpine uses musl instead of glibc. A binary linked against glibc fails on Alpine:

# Use a glibc-based image instead of Alpine:
FROM debian:12-slim

Or compile with static linking.

Check for BOM (Byte Order Mark). Some editors add a BOM at the beginning of files. This invisible character breaks the shebang line. Check with:

xxd start.sh | head -1
# Should start with 2321 (#!/) not efbb bf23 (BOM + #!/)

Remove the BOM with:

sed -i '1s/^\xEF\xBB\xBF//' start.sh

Check Docker Desktop settings. On macOS, Docker Desktop has a “Use Rosetta for x86_64/amd64 emulation on Apple Silicon” option. Enabling this can improve compatibility with amd64 images. For disk space issues preventing image pulls, see Fix: Docker no space left on device.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles