{"record":{"id":"ce4070494fd0f888","repo":"amir20/dozzle","slug":"registry-requires-authentication","errorCode":null,"errorMessage":"registry requires authentication","messagePattern":"registry requires authentication","errorType":"error_code","errorClass":"ErrAuthRequired","httpStatus":null,"severity":"info","filePath":"internal/imagecheck/registry.go","lineNumber":31,"sourceCode":"\n\t\"github.com/rs/zerolog/log\"\n)\n\n// acceptManifests lists every manifest media type we are willing to receive.\n// Multi-arch images resolve to an index/manifest-list, which is the digest\n// recorded in the local RepoDigests, so those come first.\nvar acceptManifests = strings.Join([]string{\n\t\"application/vnd.oci.image.index.v1+json\",\n\t\"application/vnd.docker.distribution.manifest.list.v2+json\",\n\t\"application/vnd.docker.distribution.manifest.v2+json\",\n\t\"application/vnd.oci.image.manifest.v1+json\",\n}, \",\")\n\nvar (\n\t// ErrAuthRequired means the registry rejected an anonymous request. Dozzle\n\t// has no credential store, so private images are reported rather than\n\t// retried.\n\tErrAuthRequired = errors.New(\"registry requires authentication\")\n\t// ErrNotFound means the tag no longer exists upstream.\n\tErrNotFound = errors.New(\"image not found in registry\")\n\t// ErrRateLimited means the registry asked us to back off.\n\tErrRateLimited = errors.New(\"registry rate limited the request\")\n)\n\ntype cachedToken struct {\n\ttoken     string\n\texpiresAt time.Time\n}\n\n// Registry resolves the current manifest digest for an image reference using\n// HEAD requests, which registries do not count against image pull rate limits.\ntype Registry struct {\n\tclient *http.Client\n\n\tmu     sync.Mutex\n\ttokens map[string]cachedToken","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/imagecheck/registry.go#L13-L49","documentation":"ErrAuthRequired means the container image registry rejected an anonymous request during an update check. Dozzle has no credential store, so it cannot authenticate to private registries; instead of retrying endlessly it surfaces this sentinel so the checker can report the image as 'auth required' rather than treating it as a transient failure.","triggerScenarios":"remoteDigest/Digest makes a manifest request without credentials and the registry answers 401 (or a token request is denied); Check and Digest propagate it, and checker.go maps it to StatusAuthRequired while deliberately NOT shortening the cache TTL (checker.go:290).","commonSituations":"Watching a private image (e.g. a paid or GHCR private package) whose tag cannot be read anonymously; Docker Hub rate-limit-style 401s for unauthenticated pulls; pulling images from a registry that requires a token even for manifest HEAD requests.","solutions":["Verify the image is publicly pullable: docker manifest inspect <image> (or curl the registry v2 manifest endpoint) without credentials.","If the image is private, accept the StatusAuthRequired status in the update-check result or stop watching that image; Dozzle will not check updates for it.","Pull the image locally with proper docker login so the local digest exists; Dozzle can still compare against the locally available digest.","If 401 is coming from Docker Hub rate limiting rather than a truly private image, wait out the rate window or use a registry mirror/proxy."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before relying on update checks\ndocker manifest inspect <image:tag> >/dev/null 2>&1 || echo 'not anonymously pullable'","typeGuard":"func isAuthRequired(err error) bool { return errors.Is(err, imagecheck.ErrAuthRequired) }","tryCatchPattern":"if err != nil {\n  if errors.Is(err, imagecheck.ErrAuthRequired) {\n    // report StatusAuthRequired; do NOT shorten TTL or retry\n    result.Status = StatusAuthRequired\n  } else { /* transient: retry with backoff */ }\n}","preventionTips":["Only watch images that are publicly pullable","Check the update-check result status for StatusAuthRequired and skip retries for it","Remember Dozzle has no credential store — pre-pull private images yourself","Treat this as permanent, not transient: it intentionally keeps the full TTL"],"tags":["docker","registry","authentication","update-check"],"backgroundTag":"authentication-required","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"}