Quick answer

A Docker exec format error most often means an AMD64 executable is being started on an ARM64 host, or the reverse. It can also mean the file targets the wrong operating system, has a missing or malformed script interpreter line, or depends on a CGO runtime that is absent.

Do not run an unknown binary just to identify it. Inspect its file header, compare it with the host and image platform, then rebuild only the mismatched layer.

Diagnose the mismatch in four checks

1. Identify the host architecture

uname -m

# Common results:
# x86_64  = AMD64
# aarch64 = ARM64

Docker containers share the host kernel. Executable code still has to be compatible with the host architecture, unless an emulator has been installed and configured.

2. Inspect the image platforms

docker buildx imagetools inspect IMAGE:TAG

# For a local image:
docker image inspect IMAGE:TAG \
  --format '{{.Os}}/{{.Architecture}}'

A multi-platform tag should expose a manifest for each supported target, such as linux/amd64 and linux/arm64. A single-platform tag can work on one machine and fail on another.

3. Inspect the executable without starting it

file ./my-service

# Or install the header-only diagnostic:
go install github.com/soul-sol/go-exec-format-doctor/cmd/go-exec-format-doctor@latest
go-exec-format-doctor ./my-service

The free go-exec-format-doctor reads file headers locally and reports the detected format, operating system, and architecture. It does not execute the inspected file.

4. Check whether the failing entrypoint is a script

head -n 1 ./entrypoint.sh
file ./entrypoint.sh

# A valid first line names an interpreter:
#!/bin/sh

A missing interpreter, Windows CRLF line endings, or a path that does not exist inside the image can surface as the same error. If the entrypoint is a script, fix that layer before rebuilding a compiled binary.

Match the evidence to the smallest useful fix
Evidence Likely cause Next action
Host is ARM64, binary is AMD64 Binary architecture mismatch Rebuild with GOARCH=arm64
Image tag lists only AMD64 Missing ARM64 manifest Publish a multi-platform image
Binary format is PE32+ Windows binary in Linux Rebuild with GOOS=linux
Entrypoint starts with text or CRLF Script header or line-ending problem Fix the shebang and convert to LF
Architecture matches, loader is missing CGO or dynamic runtime mismatch Supply target libraries or use a supported static build

Apply the fix that matches the evidence

Build the Go binary for the target platform

# Linux on Intel or AMD hosts
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
  go build -o dist/my-service-linux-amd64 ./cmd/my-service

# Linux on ARM hosts
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
  go build -o dist/my-service-linux-arm64 ./cmd/my-service

These commands are appropriate only when the program supports a pure-Go build. Setting CGO_ENABLED=0 is not a universal fix. A program that needs CGO must use a target compiler and compatible target libraries.

Publish a Docker image for AMD64 and ARM64

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag REGISTRY/IMAGE:TAG \
  --push .

The pushed tag becomes a manifest list. Docker can then select the compatible image variant for a supported host. Inspect the published tag after the build rather than assuming both variants were uploaded.

Fix a script entrypoint

# Convert CRLF to LF without changing the script logic
sed -i.bak $'s/\r$//' entrypoint.sh

# Confirm the interpreter exists inside the image
docker run --rm --entrypoint /bin/sh IMAGE:TAG \
  -c 'command -v sh'

If the image is untrusted, do not run it for diagnosis. Inspect the image configuration and extracted files in an isolated analysis environment instead.

Prevent the same failure in CI

  1. Declare supported GOOS and GOARCH pairs in a build matrix.
  2. Compile every supported pair on each change, even when only one binary is released.
  3. Run selected outputs under a compatible runner or explicit emulator. A successful compile does not prove the program starts.
  4. Inspect the final Docker manifest and record the result as a build artifact.
  5. Keep CGO targets separate because their compiler, libc, and runtime requirements differ from pure-Go targets.

Common questions

Why does the image work on my laptop but fail in production?

The two machines may use different CPU architectures. Apple Silicon is ARM64, while many production nodes are AMD64. The reverse also occurs on ARM cloud instances. Compare both platforms and inspect the image manifest.

Does Docker automatically emulate another architecture?

Not in every environment. Docker Desktop bundles convenient emulation for common workflows, but a Linux server may not have the required QEMU and binfmt configuration. Native images are usually the more predictable production choice.

Will CGO_ENABLED=0 always solve the error?

No. It produces a pure-Go build only when the application and its dependencies support one. Software that requires C code needs a target-aware compiler and compatible runtime libraries.

Can this error be caused by permissions?

A non-executable file usually produces a permission error instead. Still verify the executable bit after confirming the format, operating system, architecture, and script header.

Primary sources