Skip to main content
DevOps Insightsguides & answers

Docker · troubleshooting

blob unknown to registry

Since Docker 29.7 (BuildKit 0.32), images are built with their provenance attestation stored as an OCI artifact that points at the image manifest. Some registries, GitLab's among them, refuse that attestation when the image manifest is new in the same push and answer blob unknown to registry. Rebuild with BUILDX_NO_DEFAULT_OCI_ARTIFACT=1 (Buildx 0.36.1 or later), then push again.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 10 sections

Before you start

  • The failing push's full output, including the build output if the image was built in the same job.
  • docker version and docker buildx version from the machine or dind service that builds and pushes.
  • Permission to change the CI job's environment variables.

Run this first

step 1 of 2
docker buildx build --progress=plain --push -t REGISTRY/IMAGE:TAG . 2>&1 | grep -E 'exporting manifest|blob unknown'

Look for The rejected sha256 equals the exporting manifest digest of the image (not the attestation, not the manifest list): the attestation cause

Puts the image manifest digest from the build next to the digest the registry rejected.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Is the digest in the error the same as the build's exporting manifest digest?

Cause space

2 of 2 still possible

  • The registry rejects an attestation pushed before its imageCommon
  • The image store push path skips a blob (open report)Rare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Check it with a tool

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    docker buildx build --progress=plain --push -t REGISTRY/IMAGE:TAG . 2>&1 | grep -E 'exporting manifest|blob unknown'

    Puts the image manifest digest from the build next to the digest the registry rejected.

    Look for The rejected sha256 equals the exporting manifest digest of the image (not the attestation, not the manifest list): the attestation cause

  2. Step 2

    docker version --format '{{.Server.Version}}'
    docker buildx version

    The behaviour starts with Engine 29.7 (BuildKit 0.32); the opt-out needs Buildx 0.36.1.

    Look for 29.7 or later; Buildx v0.36.1 or later

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The registry rejects an attestation pushed before its image

Common

BuildKit 0.32 and later (Docker 29.7 and later) attach provenance as an OCI artifact whose subject is the new image manifest, and push it first. A registry that does not follow the specification's rule for subjects refuses it.

Confirm

docker buildx version
docker version --format '{{.Server.Version}}'

Buildx 0.36.1 or later and Engine 29.7 or later, plus an error digest equal to the build's exporting manifest digest

Fix

  • Set BUILDX_NO_DEFAULT_OCI_ARTIFACT=1 in the job before building, then rebuild and push. Buildx then stores the attestation in the older format, which has no subject. It needs Buildx 0.36.1 or later.
  • If you call the exporter yourself, set oci-artifact=false on it instead, for example --output type=registry,name=REGISTRY/IMAGE:TAG,oci-artifact=false.
  • Only if you do not need provenance: build with --provenance=false --sbom=false, or set BUILDX_NO_DEFAULT_ATTESTATIONS=1.
  • Rebuild after changing the setting. An image already built keeps the attestation format it was built with.
export BUILDX_NO_DEFAULT_OCI_ARTIFACT=1

Before docker build or docker buildx build; Buildx 0.36.1 or later.

The image store push path skips a blob (open report)

Rare

moby#53293 reports that with the containerd image store, Docker 29.7 skips a blob as already existing and the registry then rejects the push. It was open on 21 Oct 2026 without a confirmed cause, and the maintainers suspect most such reports are the attestation issue above.

Confirm

docker info --format '{{.DriverStatus}}'

io.containerd.snapshotter.v1, and an error digest that is a layer in the push output, not the image manifest

Fix

  • Try BUILDX_NO_DEFAULT_OCI_ARTIFACT=1 first; it resolves the common case.
  • If the digest really is a layer, add your details to moby#53293. Reporters there got pushes working again by pinning docker:29.6.2-dind.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

When Docker builds an image it also writes a small signed-off record of how it was built, called an attestation, and pushes it next to the image. From Docker 29.7 that record says which image it belongs to, in a newer standard format. The standard lets a client upload the record before the image itself, and requires registries to accept that. Some registries do not: they see a record for an image they have not received yet and reject the push, naming the image's own digest as the unknown blob.

Words used on this page

Attestation
A record pushed alongside an image, such as build provenance or an SBOM. Buildx adds a provenance attestation by default.
OCI artifact (attestation format)
From BuildKit 0.32, the attestation manifest carries a subject field that points at the image manifest it describes.
Subject / referrer
The image is the subject; the attestation that points at it is a referrer. The OCI distribution spec lets referrers be pushed before their subject.
dind
Docker-in-Docker: a docker:VERSION-dind service that CI jobs build and push through.
What is actually happening

Docker 29.7.0 updated its bundled BuildKit from 0.31.2 to 0.32.0, which stores attestations as OCI artifacts by default whenever OCI media types are in use (BuildKit #6914). The attestation manifest now has a subject: the image manifest's digest.

BuildKit pushes the attestation before the image manifest. The OCI distribution spec (v1.1.1) says a registry must initially accept a manifest whose subject does not exist yet. A registry that instead checks the subject rejects the push with blob unknown to registry and the image manifest's digest.

BuildKit briefly changed its push order to suit such registries (#7012), then reverted it (#7015), because the order it uses is the one the specification protects. So a newer Docker will not make this go away by itself.

The digest in the error is the giveaway: it is the image manifest's digest, the one the build log prints as exporting manifest, not a layer's.

A related report against the engine's own push path (moby#53293) was still open on 21 Oct 2026; a maintainer there asked whether those reporters were also using GitLab's registry.

How to tell this is your problem
WhereWhat you see
docker push or docker buildx build --pusherror from registry: blob unknown to registry - sha256:…
The build log of the same jobexporting manifest sha256:… with the same digest as the error
Push progressEvery layer shows Pushed or Layer already exists; the failure comes at the very end.
TimingStarted when the CI image or dind service moved from 29.6.x to 29.7 or later; reverting fixes it.

How to know it is actually fixed

  • The push completes and the tag is listed in the registry.
  • docker buildx imagetools inspect REGISTRY/IMAGE:TAG shows the image and its attestation manifest.

Stopping it happening again

  • Pin the dind or Docker version in CI and read the release notes before moving to a new minor version.
  • Keep BUILDX_NO_DEFAULT_OCI_ARTIFACT=1 in the job until your registry accepts referrers pushed before their subject, then remove it and test.

Security considerations

  • --provenance=false --sbom=false also makes the push work, but removes the build records that let anyone verify where the image came from. Prefer BUILDX_NO_DEFAULT_OCI_ARTIFACT=1, which keeps the provenance in the older format.
  • Pinning dind to 29.6.2 to avoid this also pins an engine that stops receiving fixes. Treat it as a short-term measure with a date on it.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it