Docker

How to Fix Docker "exec format error" When Running x86_64 Image on Apple Silicon M-Series

4 min read by DebuggedIt

Quick answer

A Docker container that runs fine on other machines fails immediately on an Apple Silicon Mac with a cryptic "exec format error." This means the image contains...

A Docker container that runs fine on other machines fails immediately on an Apple Silicon Mac with a cryptic "exec format error." This means the image contains binaries compiled for a CPU architecture (x86_64/amd64) that the M-series chip's ARM64 processor can't natively execute.

The Problem

Starting a container that worked elsewhere fails immediately on an M1/M2/M3 Mac:

$ docker run myapp:latest
standard_init_linux.go:228: exec user process caused: exec format error

It can also show up more tersely depending on the Docker version and context:

exec /usr/local/bin/myapp: exec format error
Two CPU architectures, one wrong binary Image built for: amd64 (x86_64 machine code) M-series Mac: arm64 (different instruction set) Fix: --platform linux/arm64, or QEMU emulation via --platform linux/amd64

Why It Happens

Docker images can be built for specific CPU architectures, and a binary compiled for x86_64 (amd64) contains machine code the ARM64 kernel simply cannot execute directly β€” this is a fundamental hardware incompatibility, not a Docker configuration issue in itself. Apple Silicon Macs run natively on ARM64, so any image (or specific layer within a multi-stage build) built exclusively for amd64 will fail with this exact error when run natively. Common scenarios:

  • Pulling a pre-built public image that was only published for amd64, common with older or less actively maintained images that haven't added multi-architecture support.
  • Building locally without specifying a target platform, where the build ends up targeting whatever the base image defaults to, which may not match your host architecture if a base image itself is amd64-only.
  • A CI/CD pipeline building on amd64 runners and pushing an amd64-only image, which then fails when a developer tries to run that same image locally on their M-series machine.
  • Docker Desktop's Rosetta-based emulation being disabled or misconfigured, removing the fallback that would otherwise let amd64 images run (more slowly) via translation.

The Fix

First, check what architecture the image was actually built for:

docker inspect myapp:latest --format '{{.Architecture}}'
amd64

If a native ARM64 version of the image exists (check the registry, or if it's your own build), pull or specify that platform explicitly:

docker pull --platform linux/arm64 myapp:latest

If you're building the image yourself, target the correct platform explicitly rather than relying on defaults:

docker build --platform linux/arm64 -t myapp:latest .

For multi-architecture support so the same image tag works correctly on both amd64 and arm64 machines, use buildx to build and push a manifest covering both platforms at once:

docker buildx build --platform linux/amd64,linux/arm64 -t myrepo/myapp:latest --push .

With this manifest in place, Docker automatically pulls the correct architecture-specific image for whichever machine runs docker pull or docker run, without needing any explicit platform flag from the end user.

If you specifically need to run an amd64-only image (no ARM64 version exists, and rebuilding isn't an option), Docker Desktop on Apple Silicon can run it under emulation via Rosetta or QEMU, at a real performance cost:

docker run --platform linux/amd64 myapp:latest

Confirm Rosetta-based emulation is actually enabled in Docker Desktop's settings (Settings β†’ General β†’ "Use Rosetta for x86_64/amd64 emulation on Apple Silicon"), since this significantly improves performance for emulated containers compared to falling back to plain QEMU translation.

Still Not Working?

If you're building your own multi-stage Dockerfile and only some layers fail rather than the whole image, check whether a specific base image referenced partway through the Dockerfile is itself amd64-only, even if your final stage's base image supports multi-arch correctly:

# Check every FROM line in your Dockerfile
grep "^FROM" Dockerfile
docker manifest inspect some/base-image:tag

Running docker manifest inspect against each base image shows exactly which architectures it supports β€” if one stage's base image is amd64-only, either find an equivalent multi-arch alternative or explicitly pin that specific stage's platform with --platform in the FROM instruction itself, accepting emulation for just that one build stage rather than the entire image.