{"record":{"id":"31d4707e2591bb1c","repo":"amir20/dozzle","slug":"registry-omitted-docker-content-digest-for-s","errorCode":null,"errorMessage":"registry omitted Docker-Content-Digest for %s","messagePattern":"registry omitted Docker-Content-Digest for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/imagecheck/registry.go","lineNumber":116,"sourceCode":"\t\tInt(\"status\", resp.StatusCode).\n\t\tStr(\"contentType\", resp.Header.Get(\"Content-Type\")).\n\t\tMsg(\"image update check: manifest response\")\n\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\tcase http.StatusUnauthorized, http.StatusForbidden:\n\t\treturn \"\", ErrAuthRequired\n\tcase http.StatusNotFound:\n\t\treturn \"\", ErrNotFound\n\tcase http.StatusTooManyRequests:\n\t\treturn \"\", ErrRateLimited\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"registry returned %s for %s\", resp.Status, ref.Repository)\n\t}\n\n\tdigest := resp.Header.Get(\"Docker-Content-Digest\")\n\tif digest == \"\" {\n\t\treturn \"\", fmt.Errorf(\"registry omitted Docker-Content-Digest for %s\", ref.Repository)\n\t}\n\n\tlog.Debug().Str(\"repository\", ref.Repository).Str(\"digest\", digest).Msg(\"image update check: registry digest\")\n\n\treturn digest, nil\n}\n\nfunc (r *Registry) head(ctx context.Context, ref Reference, token string) (*http.Response, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodHead, ref.manifestURL(), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Accept\", acceptManifests)\n\tif token != \"\" {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+token)\n\t}\n\n\treturn r.client.Do(req)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/imagecheck/registry.go#L98-L134","documentation":"After a successful manifest request, Digest reads the Docker-Content-Digest response header. Registries are expected to return it; if it is missing or empty, the client cannot compare remote vs local digests and returns this error.","triggerScenarios":"The manifest HEAD/GET returns a success status but the Docker-Content-Digest header is absent, which happens with proxies that strip headers, misconfigured reverse proxies, or non-OCI-compliant registries.","commonSituations":"Corporate proxies or CDNs removing response headers, custom registries that don't implement the Docker Registry v2 header contract, or a caching layer serving stale headerless responses.","solutions":["Bypass or reconfigure the proxy to pass through the Docker-Content-Digest header","Test directly: curl -I https://<registry>/v2/<repo>/manifests/<tag> and check the header","Use a compliant registry (Docker Hub, GHCR, ECR, Harbor) or upgrade the custom registry","As a fallback, fetch the manifest body and compute the sha256 digest locally"],"exampleFix":"// before\ndigest := resp.Header.Get(\"Docker-Content-Digest\")\n// after (caller-side fallback)\ndigest := resp.Header.Get(\"Docker-Content-Digest\")\nif digest == \"\" {\n    b, _ := io.ReadAll(resp.Body)\n    sum := sha256.Sum256(b)\n    digest = \"sha256:\" + hex.EncodeToString(sum[:])\n}","handlingStrategy":"fallback","validationCode":"resp, err := http.Head(manifestURL)\nif err == nil && resp.Header.Get(\"Docker-Content-Digest\") == \"\" {\n    return fmt.Errorf(\"registry does not expose Docker-Content-Digest; plan fallback\")\n}","typeGuard":null,"tryCatchPattern":"digest, err := client.Digest(ref)\nif err != nil && strings.Contains(err.Error(), \"omitted Docker-Content-Digest\") {\n    digest, err = computeDigestFromManifestBody(ref) // sha256 the manifest bytes\n}","preventionTips":["Test the registry's header contract with curl before relying on it","Reconfigure proxies/CDNs to pass through Docker-Content-Digest","Keep a local manifest-body hashing fallback for non-compliant registries"],"tags":["registry","digest","http-headers","image-update"],"backgroundTag":"unexpected-response-shape","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}