Attestation is not supported for the docker driver
Attestation is not supported for the docker driver is buildx telling you the builder you are on cannot carry attestations at all, which is a different refusal from the exporter one people usually conflate with it. Four separate programs refuse attestation builds with four different sentences, and the default provenance buildx adds on its own is not any of them.

What this error means
A build that worked stops as soon as --provenance or --sbom is set, or a --load that worked stops when someone turns attestations on. The wording depends on which program objected: buildx refuses before the build starts and prints three lines with a documentation link, while BuildKit refuses at export time with one line about manifest lists. The block below is two builds on this machine, one per driver.
--- docker buildx build --provenance=true --load, on the default docker driver
ERROR: failed to build: Attestation is not supported for the docker driver.
Switch to a different driver, or turn on the containerd image store, and try again.
Learn more at https://docs.docker.com/go/attestations/
--- the same flag on a docker-container builder, refused later and by a different program
ERROR: failed to build: docker exporter does not currently support exporting manifest listsFour refusals that people treat as one
Two of these come from buildx, before any build starts, and two from BuildKit, at the moment it tries to write the result. They fail at different times, they name different things, and the fix for one is not the fix for another. Identify yours from the wording before you change a flag.
The buildx one is assembled at runtime from a feature name, the name of your driver and a documentation URL, so the sentence you pasted exists as a literal in no source file. Searching for it will not find the code; searching for "is not supported for the" and the word driver will.
| The sentence you got | Which program refused | When it refused |
|---|---|---|
| Attestation is not supported for the <name> driver. | buildx, its not-supported helper | Before the build, from a driver feature check |
| Attestations are not supported by the current BuildKit daemon | buildx, its build option assembly | Before the build, when the daemon lacks the capability |
| docker exporter does not currently support exporting manifest lists | BuildKit, the image exporter | At export, when the result has more than one ref |
| cannot export attestations with "oci-mediatypes=false" | BuildKit, the container image writer | At export, when you forced Docker media types |
Common causes
You asked for attestations on a driver that cannot carry them
The default docker driver without the containerd image store does not report multi platform support, and buildx requires that feature before it will pass any attestation through. It refuses at the flag rather than letting the build run and fail late, which is the right call and also why the message mentions a driver rather than your Dockerfile.
A non inline attestation turned a single platform build into an index
This is the case that actually produces the exporter message. --provenance=mode=max and any --sbom write attestation manifests, which means the result is an index with more than one ref. The docker exporter refuses an index, so a --load fails at the end of an otherwise successful build. The refusal itself is the sentence we captured, from a multi platform load that reaches it the same way.
You are loading a multi platform build
Nothing to do with attestations, and it produces the identical exporter sentence, which is why the two get conflated. A --platform linux/amd64,linux/arm64 --load gives you "docker exporter does not currently support exporting manifest lists" with no attestation flags anywhere. If your build sets both, remove the platforms first and see whether the message survives.
The BuildKit daemon behind your builder is older than 0.11.0
Attestations arrived in BuildKit 0.11.0, and buildx checks for the capability rather than the version number. When the driver supports multi platform but the daemon does not advertise the attestation capability, you get "Attestations are not supported by the current BuildKit daemon" instead. In CI this usually means a pinned builder image or a self hosted buildkitd nobody has upgraded.
You forced Docker media types on an export that carries attestations
Attestation manifests can only be described in OCI media types, so setting oci-mediatypes=false on an export that has them is a contradiction and BuildKit says so directly. This tends to appear when someone fixes a registry compatibility problem with a media type flag and a supply chain requirement adds attestations later.
How to fix it
Decide whether you need the artifact loaded or pushed
- If the image is only being scanned or tested in the same job,
--loadis what you want and attestations are not. - If the image is being published, push it: the registry exporter handles indexes, so attestations and multiple platforms are both fine.
- Do not try to have both in one invocation. Build twice if you genuinely need a local image and an attested published one.
- uses: docker/build-push-action@v7
with:
context: .
load: true
provenance: false
sbom: false
tags: acme/api:ci
- uses: docker/build-push-action@v7
with:
context: .
push: true
provenance: mode=max
sbom: true
tags: ghcr.io/acme/api:1.4.2Turn on the containerd image store if you want attestations on the docker driver
This is what the message itself suggests, and it is the only way to keep the plain driver and still carry attestations, because the classic image store cannot hold an index. On a hosted runner it means configuring the daemon before the build step, which is a real cost; on a self hosted runner image it is a one time change.
# /etc/docker/daemon.json on the runner image
{
"features": { "containerd-snapshotter": true }
}Keep the default provenance and drop only what forces an index
Since the default is inline only, you do not have to give up provenance to make --load work. Leave the defaults alone and set only the flags that create separate manifests. This keeps the build metadata that ends up in the image configuration while avoiding the exporter refusal.
# loads, and still carries the default inline provenance
docker buildx build --load -t acme/api:ci .
# refuses at the exporter, because mode=max writes its own manifest
docker buildx build --provenance=mode=max --load -t acme/api:ci .Turn the defaults off globally only when you mean it
There is an environment variable that stops buildx adding its default provenance. Reach for it when a registry or a downstream tool genuinely cannot cope with the inline metadata, not as a reflex, because it is a supply chain signal you are giving up for every build in that job.
env:
BUILDX_NO_DEFAULT_ATTESTATIONS: 1The default provenance does not break --load, and we checked both drivers
It is widely repeated that buildx attaches provenance by default and that this is why --load fails. The first half is true with conditions and the second half is not. When you do not pass --provenance and the builder supports attestations, buildx sets a provenance attestation with mode=min and inline-only=true. Inline only means it goes into the image configuration rather than into a manifest of its own, so nothing becomes an index and the docker exporter has one ref to write.
On the plain docker driver buildx does not add it at all, because the default attestation is only added when the driver reports the multi platform feature. So a --load with no attestation flags has a single ref to write on either driver and the exporter takes it. What moves the boundary is the flags that write attestation manifests of their own: --provenance=mode=max, and any --sbom, since there is no inline form of one. Each of those makes the result an index, and an index is what the docker exporter refuses. The boundary is non inline attestations, not attestations in general.
| Build | Builder driver | Result |
|---|---|---|
--load, no attestation flags | docker | Loaded |
--provenance=true --load | docker | Attestation is not supported for the docker driver. |
--load, no attestation flags | docker-container | Loaded |
--provenance=mode=max --load | docker-container | docker exporter does not currently support exporting manifest lists |
--sbom=true --load | docker-container | docker exporter does not currently support exporting manifest lists |
Which driver your workflow is on decides which sentence you can get
A job that never calls docker/setup-buildx-action is on the docker driver, which is BuildKit inside the daemon. That driver reports no multi platform support unless the containerd image store is on, so it cannot carry attestations and buildx stops you at the flag. A job that does call the setup action is on a docker-container builder, which can, so the same flags get you all the way to the exporter before anything objects.
This is why the same workflow changes its error message when someone adds a setup step for an unrelated reason. Neither message is about your Dockerfile, and the fix in each case is on the output, not on the image.
# on the docker driver: attestations are refused at the flag
- run: docker buildx build --provenance=true --load .
# after this, the same build reaches the exporter instead
- uses: docker/setup-buildx-action@v4
- run: docker buildx build --provenance=true --load .Why no recorded run backs this page
Every claim on this page is a decision made by a flag and a driver feature bit, and any of the five combinations can be run locally in under a minute. A Latchkey run would add the observation that a hosted runner also has a docker driver until you install a builder, which is true and is one sentence, not a recorded job.
The part that would have needed a runner is a claim about what happens on GitHub hosted infrastructure specifically, and this page does not make one. What it makes instead is a claim about buildx and BuildKit, which are the same binaries wherever they run, and it shows the five outcomes in a table, marking which two we captured and which three we read from source, so you can repeat any of them on your own machine.
How to prevent it
- Split loading and publishing into two build invocations with different flags rather than one that has to satisfy both.
- Pin the builder image behind your
docker-containerdriver so the attestation capability does not change under a job. - Record which of your registries accept OCI indexes, because the exporter message will not tell you later.
- Treat
--loadin CI as a testing convenience and push everything you intend to keep.
Frequently asked questions
Does buildx add provenance to my builds by default?
Why does --sbom break --load when --provenance does not?
What is the difference between the driver message and the exporter message?
Do I have to give up provenance to publish to an old registry?
Related guides
References
- buildx: the helper that assembles the not-supported sentence
- buildx: where the default provenance attestation is set
- BuildKit: the exporter that refuses a manifest list
- Docker docs: build attestations
- pantsbuild/pants#21372: the exporter message on a multi platform load
- Docker documentation
- Docker build cache
- GitHub Actions documentation