amir20/dozzle · warning · ErrNotFound

image not found in registry

Error message

image not found in registry

What it means

ErrNotFound means the tag or digest being checked no longer exists upstream: the registry returned HTTP 404 for the manifest request. The image check cannot compute a remote digest because there is nothing at that reference anymore.

Solutions

  1. Run docker manifest inspect <image:tag> to confirm the tag really is gone upstream.
  2. If the tag was deleted, pin the check to a tag that exists (or the local digest) instead.
  3. Check the image name spelling and registry host (e.g. library/ prefix on Docker Hub, ghcr.io owner/repo).
  4. If you run the registry, check retention/pruning policies that may be deleting tags.
Defensive patterns

Strategy: validation

Validate before calling

docker manifest inspect <image:tag> >/dev/null 2>&1 && echo 'tag exists' || echo 'tag missing upstream'

Type guard

func isNotFound(err error) bool { return errors.Is(err, imagecheck.ErrNotFound) }

Prevention

When it happens

Trigger: Digest performs a manifest request and receives http.StatusNotFound (registry.go:107); typically the watched tag was deleted, retagged, or the image name is misspelled.

Common situations: A :latest-style mutable tag was removed upstream; a maintained image stopped publishing a specific version tag; typo in the image repository name in compose files; images pruned from a self-hosted registry.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/13f53200bf2b587b. Report an issue: GitHub.

Appendix: source

Thrown at internal/imagecheck/registry.go:33

)

// acceptManifests lists every manifest media type we are willing to receive.
// Multi-arch images resolve to an index/manifest-list, which is the digest
// recorded in the local RepoDigests, so those come first.
var acceptManifests = strings.Join([]string{
	"application/vnd.oci.image.index.v1+json",
	"application/vnd.docker.distribution.manifest.list.v2+json",
	"application/vnd.docker.distribution.manifest.v2+json",
	"application/vnd.oci.image.manifest.v1+json",
}, ",")

var (
	// ErrAuthRequired means the registry rejected an anonymous request. Dozzle
	// has no credential store, so private images are reported rather than
	// retried.
	ErrAuthRequired = errors.New("registry requires authentication")
	// ErrNotFound means the tag no longer exists upstream.
	ErrNotFound = errors.New("image not found in registry")
	// ErrRateLimited means the registry asked us to back off.
	ErrRateLimited = errors.New("registry rate limited the request")
)

type cachedToken struct {
	token     string
	expiresAt time.Time
}

// Registry resolves the current manifest digest for an image reference using
// HEAD requests, which registries do not count against image pull rate limits.
type Registry struct {
	client *http.Client

	mu     sync.Mutex
	tokens map[string]cachedToken
}

View on GitHub (pinned to d9463cbe21)