16.1.2.5 Build Architecture Mismatch
A focused guide to Build Architecture Mismatch, connecting core concepts with practical Docker and container operations.
A build architecture mismatch occurs when an image is built for one CPU architecture but run on infrastructure using a different one, most commonly x86-64 versus ARM64 given the rise of ARM-based development machines and cloud instances, producing a failure that can range from an immediate, obvious error to a successful-looking container that crashes or misbehaves once it actually tries to execute architecture-specific code.
The most direct symptom
When an image built for one architecture is run on incompatible hardware with no emulation available, the failure is usually immediate and explicit:
docker run my-api:1.4.0
standard_init_linux.go:228: exec user process caused: exec format error
This specific error message is a strong, recognizable signal of an architecture mismatch, distinct from most other container startup failures, and is usually the fastest confirmation that this category of problem, rather than an application bug, is the actual cause.
Checking an image's actual architecture
Before assuming a mismatch, confirming the architecture an image was actually built for, and comparing it against the architecture of the host attempting to run it, resolves any ambiguity directly:
docker image inspect my-api:1.4.0 --format '{{.Architecture}}'
uname -m
A clear mismatch between these two values, arm64 reported by the image versus x86_64 reported by the host, or vice versa, confirms the cause immediately rather than leaving it as a hypothesis.
Building for a specific target platform
The --platform flag on docker build explicitly controls which architecture the resulting image targets, which is necessary whenever the build machine's native architecture differs from the deployment target's:
docker build --platform=linux/amd64 -t my-api .
docker build --platform=linux/arm64 -t my-api .
Without this flag, a build typically defaults to the build machine's own native architecture, which is the source of many mismatches: a developer building locally on an ARM-based machine, then deploying without realizing the image was never built for the x86-64 production infrastructure it was about to run on.
Building multi-architecture images
For images that need to run correctly on more than one architecture, docker buildx supports building and pushing a single image reference that actually resolves to the correct architecture-specific variant automatically when pulled:
docker buildx build --platform=linux/amd64,linux/arm64 -t registry.example.com/my-api:1.4.0 --push .
This produces a manifest list, a single tag that internally points to multiple architecture-specific image variants, and the container runtime pulling this tag automatically selects the variant matching its own host architecture, removing the need for separate, architecture-specific tags managed manually.
docker manifest inspect registry.example.com/my-api:1.4.0
Inspecting the manifest list directly confirms which architectures are actually included, which is a useful verification step after a multi-architecture build and push, before assuming every intended target architecture was successfully built and published.
Emulation during cross-architecture builds
Building for an architecture different from the build machine's own native one generally requires emulation, commonly through QEMU, which docker buildx sets up automatically in many environments but which can fail or behave unexpectedly if the necessary emulation support is not correctly registered:
docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx ls
Verifying that the buildx builder instance actually supports the target platforms being requested, rather than assuming emulation support is automatically and correctly configured, is a useful diagnostic step when a cross-architecture build fails in a way that does not point to anything obviously wrong with the Dockerfile itself.
Native dependencies and cross-compilation
Beyond the base image's own architecture, dependencies with native, compiled components need to be correctly built for the target architecture as well, which can fail or, more subtly, succeed while producing a binary that does not actually match the target architecture if the build process does not correctly account for cross-compilation:
RUN npm rebuild --target_arch=arm64
A native dependency that appears to install successfully during an emulated cross-architecture build, but that actually contains a binary built for the wrong architecture due to a build script not correctly detecting the cross-compilation target, can produce a confusing failure that only manifests once the container actually runs on the genuinely different target hardware, well after the build itself reported success.
Performance differences between native and emulated builds
Builds running under emulation for a non-native architecture are typically significantly slower than a native build for the build machine's own architecture, which is worth accounting for when estimating CI pipeline duration or when deciding whether to build on architecture-matched infrastructure directly rather than relying on emulation:
time docker buildx build --platform=linux/arm64 -t my-api .
For organizations building multi-architecture images regularly, using actual native build infrastructure for each target architecture (separate native ARM and x86 build runners, for instance, rather than emulating one from the other) often resolves both the performance cost and any subtle native-dependency cross-compilation issues simultaneously.
Verifying the running container's actual architecture
After deployment, confirming that a running container is actually using the architecture-appropriate image variant, rather than assuming a multi-architecture manifest resolved correctly, closes the loop on this category of issue:
docker exec my-api uname -m
A mismatch here, despite having built and pushed what was intended to be a correct multi-architecture image, points toward either a manifest list that did not actually include the needed architecture, or a deployment process that pulled or cached an incorrect, architecture-mismatched variant.
Common mistakes
- Building locally on a machine with a different native architecture than the deployment target without explicitly specifying
--platform, defaulting to the wrong architecture. - Assuming a successful cross-architecture build guarantees correctly compiled native dependencies, without verifying the actual architecture of any compiled binaries the build produced.
- Not verifying that a buildx builder instance actually supports the requested target platforms before relying on it for a cross-architecture build.
- Underestimating how much slower emulated cross-architecture builds are compared to native builds when planning CI pipeline timing.
- Pushing a multi-architecture manifest without directly inspecting it afterward to confirm every intended architecture variant was actually included successfully.
A build architecture mismatch is one of the more unambiguous categories of Docker failure to diagnose, given the specific "exec format error" symptom and the directly inspectable architecture metadata on both image and host, and avoiding it going forward is mostly a matter of explicitly specifying target platforms during builds rather than relying on whatever a build machine's own native architecture happens to default to.