amir20/dozzle · error
registry omitted Docker-Content-Digest for
Error message
registry omitted Docker-Content-Digest for %s
What it means
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.
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
Example fix
// before
digest := resp.Header.Get("Docker-Content-Digest")
// after (caller-side fallback)
digest := resp.Header.Get("Docker-Content-Digest")
if digest == "" {
b, _ := io.ReadAll(resp.Body)
sum := sha256.Sum256(b)
digest = "sha256:" + hex.EncodeToString(sum[:])
} Defensive patterns
Strategy: fallback
Validate before calling
resp, err := http.Head(manifestURL)
if err == nil && resp.Header.Get("Docker-Content-Digest") == "" {
return fmt.Errorf("registry does not expose Docker-Content-Digest; plan fallback")
} Try / catch
digest, err := client.Digest(ref)
if err != nil && strings.Contains(err.Error(), "omitted Docker-Content-Digest") {
digest, err = computeDigestFromManifestBody(ref) // sha256 the manifest bytes
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- registry returned for
- registry requires authentication
- image not found in registry
- registry rate limited the request
- invalid image reference
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/31d4707e2591bb1c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/imagecheck/registry.go:116
Int("status", resp.StatusCode).
Str("contentType", resp.Header.Get("Content-Type")).
Msg("image update check: manifest response")
switch resp.StatusCode {
case http.StatusOK:
case http.StatusUnauthorized, http.StatusForbidden:
return "", ErrAuthRequired
case http.StatusNotFound:
return "", ErrNotFound
case http.StatusTooManyRequests:
return "", ErrRateLimited
default:
return "", fmt.Errorf("registry returned %s for %s", resp.Status, ref.Repository)
}
digest := resp.Header.Get("Docker-Content-Digest")
if digest == "" {
return "", fmt.Errorf("registry omitted Docker-Content-Digest for %s", ref.Repository)
}
log.Debug().Str("repository", ref.Repository).Str("digest", digest).Msg("image update check: registry digest")
return digest, nil
}
func (r *Registry) head(ctx context.Context, ref Reference, token string) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodHead, ref.manifestURL(), nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", acceptManifests)
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
return r.client.Do(req)View on GitHub (pinned to d9463cbe21)