Docker image does not match the specified platform in CI
Docker image does not match the specified platform means the daemon found the reference you named and refused to hand it over, because the image it holds is built for a different operating system or architecture than the one your command asked for. Nothing is corrupt and nothing failed to download: the daemon is declining to pretend that an amd64 image is an arm64 image.

What this error means
A pull, a run or a compose up stops on a message that names your image and two platforms, and the job had been working until somebody added a --platform flag, switched a runner to arm64, or introduced a matrix with two architectures in it. The exact wording depends on which Docker the runner has, which matters more here than on most errors: the message was rewritten in the Docker 27 series, so the line in your log may not match the line in the answer you found.
image with reference myorg/api:1.4.2 was found but its platform (linux/amd64) does not match the specified platform (linux/arm64)Which wording you get tells you which Docker you are on
This message has two forms and they are the same failure. The daemon emits it from daemon/images/image.go in moby, and the format string there changed during the 27 series: releases up to v27.3.1 print the older wording that names a wanted and an actual platform, and v27.4.0 onward print the newer wording that puts both platforms in parentheses. Nothing about the behavior changed with it.
This matters in CI because the runner image is usually older than the newest Docker. When we read the GitHub-hosted image manifests on 2026-09-21, ubuntu-22.04 and ubuntu-24.04 both listed Docker Client and Server 28.0.4, so a job on a hosted Linux runner prints the newer wording, while most of the answers written about this error quote the older one.
| Docker Engine release | The wording the daemon prints |
|---|---|
| v20.10 through v27.3.1 | was found but does not match the specified platform: wanted <p>, actual: <p> |
| v27.4.0 through v28.5.2 | was found but its platform (<p>) does not match the specified platform (<p>) |
| On GitHub-hosted ubuntu-22.04 and ubuntu-24.04 | Docker 28.0.4, so the second form |
Common causes
The local store holds the image for one platform only
The dominant cause. An earlier pull, build or load put a single-architecture image under that reference, and a later command asked for a platform it cannot serve. The reference resolves, which is why the error says the image was found, and the platforms disagree, which is why it stops there.
The image was never published for the platform you want
Some images exist for amd64 and nothing else, and no local action will change that. Inspecting the registry rather than the local store is what separates this from the cache case, and the two have completely different fixes: one is a re-pull, the other is a build.
A matrix introduced a second architecture and nothing else changed
In our experience this is the version that reaches CI. A workflow gains an arm64 leg, every reference in it stays the same, and the legs that were fine keep being fine while the new one cannot resolve images that only ever existed for x64.
The requested platform came from somewhere you did not look
A platform: key in a compose file, a DOCKER_DEFAULT_PLATFORM variable exported by an earlier step, or a --platform on a builder can all set the request without appearing on the command that failed. When the platforms in the message are not the ones you expected, the request is what to check first.
How to fix it
Publish a manifest list covering every platform you consume
- Build with buildx for all target platforms in the job that publishes the image.
- Confirm the list with
docker buildx imagetools inspectbefore anything depends on it. - Drop the per-caller
--platformflags once the list exists, so callers stop needing to know.
docker buildx build --platform linux/amd64,linux/arm64 -t myorg/api:1.4.2 --push .
docker buildx imagetools inspect myorg/api:1.4.2Clear the stale entry, then pull for the platform you need
When the registry does have the platform and the local store is the problem, remove the cached image and pull again with the platform stated. Removing first matters: a pull that finds a matching reference may not replace an entry recorded under a different architecture.
docker image rm myorg/api:1.4.2 || true
docker pull --platform linux/arm64 myorg/api:1.4.2Set the platform once for the job rather than per command
If a whole job targets one architecture, say so once in the job environment instead of threading a flag through every command. One place to read is one place to change when the matrix grows, and it stops half the commands in a job disagreeing with the other half.
jobs:
arm:
runs-on: ubuntu-24.04-arm
env:
DOCKER_DEFAULT_PLATFORM: linux/arm64Print the platform in the job before anything depends on it
One inspect line in the log turns this error from a surprise into a fact you already had. Record what the store holds and what the runner is, right after the pull, so the next failure is diagnosed from the log instead of from a rerun.
docker image inspect "$IMAGE" --format '{{.Os}}/{{.Architecture}}'
uname -mA cached single-arch image is the usual reason
The daemon stores an image against the platform it fetched, and a plain pull fetches the platform of the host. When a later command asks for a different platform, the store has an entry under that reference that cannot satisfy it, and rather than silently running the wrong architecture the daemon refuses. The refusal is the feature; the confusion is that the reference clearly exists.
In a pipeline this shows up when one job pulls for the runner architecture and a later job, or a later matrix leg, asks for another. It also shows up on developer machines with an arm64 laptop and an amd64 registry image, which is why so many reports of this error come from people who were not doing anything with CI at all.
# what is actually in the store, and for which platform
docker image inspect myorg/api:1.4.2 --format '{{.Os}}/{{.Architecture}}'
# what the registry can offer
docker buildx imagetools inspect myorg/api:1.4.2The durable fix is a manifest list, not a flag
Pulling with an explicit platform solves the job in front of you and leaves the next one exposed, because it fixes the request rather than the image. If an image is used from more than one architecture, publish it for more than one architecture, and then no caller needs a flag at all.
Build the manifest list once in the job that publishes, and check it once in the job that consumes. An image that advertises two platforms satisfies both requests from the same reference, and the error stops being reachable rather than being handled.
- name: Build and push a manifest list
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64
push: true
tags: myorg/api:1.4.2What the runner does about it
No repair, and no recorded run. The reason is the shape of the reproduction rather than any shyness about the result: an honest capture of this failure needs two architectures present in one place, because the whole error is a disagreement between a stored platform and a requested one. Our reproduction harness runs x64 Linux runners, so anything we recorded would show us passing --platform linux/arm64 to a daemon that had never held an arm64 image, which demonstrates the message without demonstrating the condition that produces it in real pipelines.
The source settles what the message says and the runner image manifests settle which wording you will see, which is what this page needed. If you want the failure in front of you on a runner, add an arm64 leg to a matrix that pulls a single-arch image, and you will have it in one run.
How to prevent it
- Publish multi-arch manifest lists for any image more than one architecture consumes.
- Keep the requested platform in one place per job, not on individual commands.
- Inspect the registry, not the local store, before concluding a platform does not exist.
- Log the image platform and the runner architecture once per job that pulls images.
Frequently asked questions
Why does the message look different from every answer I can find?
Is the image broken or missing?
Does --platform on docker run fix this permanently?
Which component emits this message, the CLI or the daemon?
daemon/images/image.go and travels back to the client inside an API error, which is why it reaches your terminal behind the Error response from daemon: prefix the CLI adds. The CLI does not decide anything about platform matching.Related guides
References
- moby v28.0.4: the platform mismatch format string, daemon/images/image.go
- moby/moby#48643: improving these errors to reduce ambiguity between platforms
- actions/runner-images: the ubuntu-24.04 image contents, including the Docker version
- Docker docs: multi-platform builds and manifest lists
- Docker documentation
- Docker build cache
- GitHub Actions documentation