docker/cli · critical
manifest verification failed for digest
Error message
manifest verification failed for digest %s
What it means
validateManifestDigest recomputes the manifest digest from its canonical payload. When you pull by digest (@sha256:...) and the computed digest differs from the one you requested, the manifest does not match — a sign of corruption, tampering, or a digest mismatch. Pulls by tag skip this check.
Solutions
- Double-check the requested digest string for typos (length, algorithm prefix).
- Re-pull from a trusted mirror to rule out in-flight corruption.
- Re-push the image to refresh manifest and digest.
- Inspect for a MITM/proxy modifying payloads; pin to content-trusted registries.
Example fix
// before ref, _ := reference.WithDigest(name, badDigest) c.GetManifest(ctx, ref) // -> manifest verification failed // after ref, _ := reference.WithDigest(name, correctDigest) // copy digest exactly c.GetManifest(ctx, ref)
Defensive patterns
Strategy: validation
Validate before calling
// Recompute and compare the manifest digest client-side before trusting it.
func checkDigest(mfst distribution.Manifest, want digest.Digest) error {
_, canon, err := mfst.Payload()
if err != nil {
return err
}
if got := digest.FromBytes(canon); got != want {
return fmt.Errorf("digest mismatch: got %s want %s", got, want)
}
return nil
} Prevention
- Copy digests verbatim; verify length and algorithm prefix.
- Pull from trusted registries and pin by digest.
- Watch for proxies/CDNs that mutate content.
- Re-push images when digests drift.
When it happens
Trigger: Pulling a manifest by digest where the registry-returned manifest's recomputed digest does not equal the requested digest — wrong content served, transit corruption, or a hand-typed wrong digest.
Common situations: Digest copied incorrectly; registry serving stale/wrong content for the digest; content mutated by a proxy; manifest re-signed or repackaged under the same digest by mistake.
Related errors
- image config verification failed for digest
- error: username is required
- error: password is required
- conflicting options: cannot specify both --password and…
- the --password-stdin option requires --username to be set
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/0884a491546733e8.
Report an issue: GitHub.
Appendix: source
Thrown at internal/registryclient/fetcher.go:147
return configJSON, nil
}
// validateManifestDigest computes the manifest digest, and, if pulling by
// digest, ensures that it matches the requested digest.
func validateManifestDigest(ref reference.Named, mfst distribution.Manifest) (ocispec.Descriptor, error) {
mediaType, canonical, err := mfst.Payload()
if err != nil {
return ocispec.Descriptor{}, err
}
desc := ocispec.Descriptor{
Digest: digest.FromBytes(canonical),
Size: int64(len(canonical)),
MediaType: mediaType,
}
// If pull by digest, then verify the manifest digest.
if digested, isDigested := ref.(reference.Canonical); isDigested && digested.Digest() != desc.Digest {
return ocispec.Descriptor{}, fmt.Errorf("manifest verification failed for digest %s", digested.Digest())
}
return desc, nil
}
// pullManifestList handles "manifest lists" which point to various
// platform-specific manifests.
func pullManifestList(ctx context.Context, ref reference.Named, repo distribution.Repository, mfstList manifestlist.DeserializedManifestList) ([]types.ImageManifest, error) {
if _, err := validateManifestDigest(ref, mfstList); err != nil {
return nil, err
}
infos := make([]types.ImageManifest, 0, len(mfstList.Manifests))
for _, manifestDescriptor := range mfstList.Manifests {
manSvc, err := repo.Manifests(ctx)
if err != nil {
return nil, err
}View on GitHub (pinned to 4f84911bfe)