Skip to content
Latchkey LogoLatchkey home

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.

Diagram of four refusals for attestation builds and which program produces each one
Four refusals, four programs. Only the first is "Attestation is not supported for the docker driver."; the second is "docker exporter does not currently support exporting manifest lists".

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.

Captured locally on Docker 29.6.2 and buildx v0.35.0-desktop.2, 2026-09-21
--- 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 lists

Four 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 gotWhich program refusedWhen it refused
Attestation is not supported for the <name> driver.buildx, its not-supported helperBefore the build, from a driver feature check
Attestations are not supported by the current BuildKit daemonbuildx, its build option assemblyBefore the build, when the daemon lacks the capability
docker exporter does not currently support exporting manifest listsBuildKit, the image exporterAt export, when the result has more than one ref
cannot export attestations with "oci-mediatypes=false"BuildKit, the container image writerAt 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

  1. If the image is only being scanned or tested in the same job, --load is what you want and attestations are not.
  2. If the image is being published, push it: the registry exporter handles indexes, so attestations and multiple platforms are both fine.
  3. Do not try to have both in one invocation. Build twice if you genuinely need a local image and an attested published one.
.github/workflows/build.yml
- 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.2

Turn 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.

daemon.json
# /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.

Terminal
# 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.

.github/workflows/build.yml
env:
  BUILDX_NO_DEFAULT_ATTESTATIONS: 1

The 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.

BuildBuilder driverResult
--load, no attestation flagsdockerLoaded
--provenance=true --loaddockerAttestation is not supported for the docker driver.
--load, no attestation flagsdocker-containerLoaded
--provenance=mode=max --loaddocker-containerdocker exporter does not currently support exporting manifest lists
--sbom=true --loaddocker-containerdocker 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.

.github/workflows/build.yml
# 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-container driver 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 --load in CI as a testing convenience and push everything you intend to keep.

Frequently asked questions

Does buildx add provenance to my builds by default?
It adds a provenance attestation with mode set to min and inline only set to true, but only when the driver reports multi platform support. On the plain docker driver it adds nothing. Inline only means the metadata goes into the image configuration rather than a separate manifest, which is why the default does not stop a load.
Why does --sbom break --load when --provenance does not?
Because there is no inline form of an SBOM. Any SBOM attestation is written as its own manifest, which makes the result an index, and the docker exporter refuses an index. The default provenance avoids that by living in the image configuration.
What is the difference between the driver message and the exporter message?
The driver message comes from buildx before the build starts and means this builder cannot carry attestations at all. The exporter message comes from BuildKit at the end and means the build succeeded but its result cannot be written in the format you asked for. The first is fixed by changing builder, the second by changing output.
Do I have to give up provenance to publish to an old registry?
Often yes, because attestation manifests require OCI media types and BuildKit will tell you directly that it cannot export attestations with Docker media types forced. Treat that as a concession to one destination rather than a default, and keep attestations on for registries that accept them.

Related guides

References

Latchkey runs signed, attested builds at $0.0025/min at 2 vCPU with a layer cache that persists between jobs. Start free → 30-day trial · No credit card