Docker
exec format error
troubleshooting
container issues
/usr/bin/sh

Docker exec /usr/bin/sh exec format error

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

The exec /usr/bin/sh: exec format error means Docker cannot execute the container's entrypoint binary because it was compiled for a different CPU architecture than the host. This almost always comes down to running an ARM image on an x86_64 machine (or the reverse). The Linux kernel does not care that Docker is involved. If the binary's ELF header declares aarch64 but the host CPU is x86_64, the kernel refuses to load it and returns ENOEXEC, which Docker surfaces as "exec format error."

A less common but equally frustrating cause is a shell script entrypoint that is missing a proper shebang line or was saved with Windows-style line endings.

Diagnosing the Root Cause

Before applying any fix, confirm what is actually mismatched.

Check the host architecture:

bash
uname -m
# x86_64, aarch64, armv7l, etc.

Check the image architecture:

bash
docker inspect --format='{{.Os}}/{{.Architecture}}' your_image:tag
# Example output: linux/arm64

Check the image manifest for available platforms:

bash
docker manifest inspect --verbose your_image:tag | grep architecture

If the host says x86_64 but the image says arm64, you have found the problem.

Check for shebang issues in entrypoint scripts:

bash
docker run --rm --entrypoint cat your_image:tag /entrypoint.sh | head -1
# Should show: #!/bin/sh or #!/bin/bash

If the first line is not a valid shebang, or if file entrypoint.sh reports "ASCII text, with CRLF line terminators," the script will fail with the same error even on the correct architecture.

Fix 1: Pull the Correct Platform Image

Docker Hub images often publish multi-architecture manifests. You can pull a specific platform explicitly:

bash
docker pull --platform linux/amd64 node:20-alpine

This forces Docker to download the amd64 variant regardless of what the host architecture auto-detection would choose. This is the simplest fix when a multi-arch image exists.

Fix 2: Rebuild for the Target Architecture

If you own the Dockerfile, rebuild it for the correct platform:

bash
docker build --platform linux/amd64 -t myapp:latest .

For broader compatibility, build for multiple architectures using Docker Buildx:

bash
1# Create a builder instance (one-time setup)
2docker buildx create --name multiarch --use
3
4# Build and push multi-arch image
5docker buildx build \
6  --platform linux/amd64,linux/arm64 \
7  -t myregistry/myapp:latest \
8  --push .

The resulting manifest list allows Docker on any supported platform to pull the correct variant automatically.

Fix 3: Enable QEMU Emulation

When you need to run an image built for a different architecture and cannot rebuild it, QEMU user-mode emulation lets the kernel translate foreign binaries on the fly:

bash
1# Register QEMU handlers (one-time, persists until reboot)
2docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
3
4# Now you can run ARM images on x86_64
5docker run --platform linux/arm64 arm64v8/alpine:3.19 uname -m
6# Output: aarch64

Emulation is slower than native execution (expect 3-10x overhead depending on the workload), but it is invaluable for testing and CI pipelines.

Fix 4: Fix the Entrypoint Script

If the architecture matches but you still get the error, the problem is almost certainly the entrypoint script.

Add a shebang line:

dockerfile
1# Dockerfile
2COPY entrypoint.sh /entrypoint.sh
3RUN chmod +x /entrypoint.sh
4ENTRYPOINT ["/entrypoint.sh"]

The script must start with a valid shebang:

bash
1#!/bin/sh
2set -e
3echo "Starting application..."
4exec "$@"

Fix Windows line endings:

bash
# Convert CRLF to LF before building
sed -i 's/\r$//' entrypoint.sh

Or add a conversion step in the Dockerfile:

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

Fix 5: Use the Exec Form for ENTRYPOINT

Docker has two entrypoint formats. The shell form wraps your command in /bin/sh -c, which can mask or cause format errors:

dockerfile
1# Shell form - invokes /bin/sh -c, can cause issues
2ENTRYPOINT ./myapp
3
4# Exec form - runs the binary directly, preferred
5ENTRYPOINT ["/myapp"]

When using the exec form, Docker calls the binary directly without involving /bin/sh. If the binary itself is for the wrong architecture, you get a clearer error. If /bin/sh is the wrong architecture (e.g., in a scratch-based image that has no shell), the shell form fails with exec format error even if your binary is correct.

Common Causes at a Glance

CauseSymptomFix
Architecture mismatch (ARM image on x86)Error on container startPull correct platform or rebuild
Architecture mismatch (x86 image on ARM Mac)Error on container startdocker pull --platform linux/amd64 + Rosetta/QEMU
Missing shebang in entrypoint scriptError on container startAdd #!/bin/sh as first line
Windows CRLF line endings in scriptError on container startConvert to LF with sed or .gitattributes
Shell form ENTRYPOINT with no /bin/shError on container startSwitch to exec form ENTRYPOINT ["/myapp"]
Corrupt or incomplete image layersError on container startdocker pull again to re-download

Apple Silicon (M1/M2/M3) Specifics

Apple Silicon Macs run aarch64 (ARM64). Many Docker images are still published only as linux/amd64. Docker Desktop for Mac includes Rosetta 2 emulation, but it must be enabled:

text
Docker Desktop -> Settings -> General -> "Use Rosetta for x86_64/amd64 emulation on Apple Silicon"

With Rosetta enabled, linux/amd64 images run transparently on ARM Macs. Without it, you either need QEMU emulation (slower) or native ARM images.

When building images on an M1/M2/M3 Mac that will be deployed to x86_64 Linux servers, always specify the platform explicitly:

bash
docker build --platform linux/amd64 -t myapp:latest .

Otherwise, Docker defaults to linux/arm64, and the image will fail on the target server with the exact error this article describes.

Preventing the Error in CI/CD

In CI/CD pipelines, architecture mismatches often happen silently because the build machine and the deployment target differ. Add a platform check to your pipeline:

bash
1# In your CI script, after building
2EXPECTED_ARCH="amd64"
3ACTUAL_ARCH=$(docker inspect --format='{{.Architecture}}' myapp:latest)
4if [ "$ACTUAL_ARCH" != "$EXPECTED_ARCH" ]; then
5  echo "ERROR: Image built for $ACTUAL_ARCH but expected $EXPECTED_ARCH"
6  exit 1
7fi

Common Pitfalls

Assuming Docker handles architecture differences automatically. Docker pulls the manifest matching your host architecture. If the image only has one variant and it does not match your host, Docker pulls it anyway and fails at runtime, not at pull time.

Forgetting --platform when building on Apple Silicon for Linux deployments. This is the number one cause of this error in 2024-2025 era development. Always set --platform linux/amd64 explicitly when building for x86_64 targets.

Ignoring .gitattributes for line endings. If your repository has shell scripts checked in with autocrlf=true, Git converts LF to CRLF on Windows checkouts. Add *.sh text eol=lf to .gitattributes to prevent this.

Using FROM scratch without understanding the consequences. A scratch-based image has no shell, no filesystem tools, nothing. Any ENTRYPOINT in shell form will fail because /bin/sh does not exist. Always use exec form with scratch.

Not checking docker buildx ls for available builders. If Buildx is not configured, multi-platform builds silently fall back to single-platform. Verify your builder supports the target platforms.

Summary

  • The exec format error means the binary's CPU architecture does not match the host kernel, or the entrypoint script is malformed.
  • Check uname -m on the host and docker inspect on the image to confirm the mismatch.
  • Pull the correct platform with --platform linux/amd64 (or linux/arm64).
  • Use Docker Buildx for multi-architecture builds when your image needs to run on multiple platforms.
  • Enable QEMU emulation for cross-architecture testing when rebuilding is not an option.
  • Check entrypoint scripts for missing shebangs and Windows line endings.
  • On Apple Silicon Macs, enable Rosetta in Docker Desktop and always specify --platform when building for x86_64 deployment targets.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.