exec format error

Docker exec format error on Apple Silicon: fix multi-arch builds

Docker build fails with 'exec format error' on Apple Silicon when the base image architecture doesn't match your Mac. Fix it by adding --platform or switching base images.

You're on an M1, M2, or M3 Mac. You run docker build on a Dockerfile that pulls something like node:18 or python:3.11, and the build dies almost immediately with:

standard_init_linux.go:228: exec user process caused: exec format error

Or you see it mid-build when a RUN line tries to execute a binary. Sometimes it shows up in docker run instead, right after the container starts. Either way, the container can't execute the binary inside it because the binary is the wrong architecture for the kernel that's trying to run it.

What's actually going on

Apple Silicon is ARM64 (aarch64). Most public Docker images on Docker Hub are built for AMD64 (x86_64) because that's what 99% of servers run. When you pull someimage:latest on your Mac, you usually get the AMD64 variant unless the image publisher explicitly published a multi-arch manifest or an ARM64 tag.

Docker Desktop on Mac runs containers inside a Linux VM. That VM's kernel is ARM64. So when Docker tries to run an x86_64 binary on an ARM64 kernel, the kernel says "I don't know this format" and you get exec format error. It's the Linux equivalent of trying to run a Windows .exe on macOS.

The culprit here is almost always one of three things: a base image with no ARM64 variant, an explicit --platform=linux/amd64 somewhere in your chain, or a binary you downloaded inside the build (like a Go cross-compiled tool or a prebuilt CLI) that's x86_64 even though the rest of the image is fine.

The fix, step by step

  1. Figure out what architecture you're actually getting. Run this before you do anything else:
docker image inspect yourbaseimage:tag --format '{{.Os}}/{{.Architecture}}'

If it says linux/amd64, that's your problem. If it says linux/arm64, your base image is fine and the issue is a binary you're pulling in at build time.

  1. Check for a hard-coded platform flag. Search your Dockerfile and any docker build wrapper scripts:
grep -rn -- "--platform" Dockerfile* docker-compose*.yml .github/ Makefile 2>/dev/null

If you see FROM --platform=linux/amd64 node:18, that's forcing AMD64 even on ARM. Remove it unless you have a real reason to keep it.

  1. Pick the right base image. Most official images now ship multi-arch. Instead of pinning a platform, just let Docker pick:
FROM node:20-bookworm-slim
# no --platform flag, Docker picks native arch

If the image you need has no ARM64 variant (some older Java images, a few vendor SDKs, plenty of niche tooling), you have two options: switch to a base that does, or cross-build with Buildx (step 5).

  1. If you must run AMD64, install QEMU support. Docker Desktop bundles QEMU these days, so this usually just works:
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

Then build with the platform flag and expect a 3–10x slowdown:

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

Don't do this for day-to-day dev. It's slow, and any file-mounting tooling gets weird. It's for producing x86 artifacts when you can't build native.

  1. Use Buildx for real multi-arch output. If your goal is to push an image that runs on both architectures, this is the real fix. Set up a builder once:
docker buildx create --name multiarch --use

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t yourrepo/yourapp:latest \
  --push .

You need --push (or --load for single-platform) because the local Docker daemon can't hold a multi-arch manifest. Pushing to a registry is how the manifest gets created.

  1. Fix the downloaded binary case. If your base image is ARM64 but the build still fails on a RUN ./some-tool, you're pulling an x86_64 binary at build time. Common offenders: old Terraform releases, some AWS CLI install scripts, a handful of Go CLI tools, and anything shipped as a tarball without an ARM64 build. Check the release page and grab the correct linux_arm64 or linux_arm64.tar.gz asset. If the project genuinely doesn't ship ARM64, you'll have to cross-build that one binary or wrap it in QEMU.

If it still fails

  • Docker Desktop is out of date. Buildx and QEMU support on Apple Silicon has improved a lot. Anything below 4.20 is asking for trouble. Update it.
  • You're on an old Dockerfile that pulls debian:stretch or similar. Old Debian and Ubuntu base images don't have ARM64 variants. Move to bookworm, jammy, or alpine.
  • Your local docker-compose.yml sets platform: linux/amd64 under a service. This is sneaky and easy to miss because it's not in the Dockerfile. Grep the whole repo.
  • You're building inside CI but testing locally. Make sure both use the same platform. A build that works in GitHub Actions (which defaults to AMD64 runners) will not necessarily behave the same in your local ARM64 setup, and vice versa.
  • Check for a stale builder. Run docker buildx ls. If you're accidentally still on the default builder, docker buildx use multiarch to switch back.

Don't bother reinstalling Docker or nuking the VM over this. It won't help. exec format error is almost never a Docker Desktop bug — it's an architecture mismatch, every time. Fix the mismatch and the error goes away.

Related Errors in Programming & Dev Tools
java.lang.OutOfMemoryError: Java heap space Fix Java OutOfMemoryError: Java heap space SyntaxError: Unexpected token Fix 'Unexpected token' JSON parse error in fetch API 0X80004028 Fixing CO_E_CLRNOTAVAILABLE (0x80004028): CLR Not Available 0X0000FFFF FACILITY_WIN32 (0x0000FFFF): The Quick Fix That Works

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.