Docker Hub digest lookup returns stale cached digest for mutable tags
Discussed in https://github.com/renovatebot/renovate/discussions/45598
When looking up a digest on Docker Hub, getDigest() first checks DockerHubCache. If the cache has a digest for the tag, Renovate returns it without asking the registry (lib/modules/datasource/docker/index.ts, the getDigestForTag and getArchDigestForTag shortcuts added in #42724).
That cache is only refreshed by reconcile(), which only runs from _getDockerHubTags(), which only runs via getReleases(). The cache is kept for 90 days (dockerhub-cache.ts). A digest-only dependency on a mutable, unversioned tag (e.g. next@sha256:...) never calls getReleases(). So once the cache has an entry, Renovate keeps returning that digest until another lookup refreshes it or the entry expires.
This causes stale digests, and also backwards "updates": Renovate proposes the old cached digest over a newer one that was pinned manually.
Reproduction: https://github.com/woodpecker-ci/infrastructure.
The
woodpeckerci/autoscaler:nextdigest stayed stuck on a 2026-08-15 image, and https://github.com/woodpecker-ci/infrastructure/pull/490 reverted a newer manual pin. Root-cause analysis: #45598
Proposed fix: do not use DockerHubCache for digest lookups. Always do the HEAD manifest request. It's one cheap request per dependency, and it's what non-Docker Hub registries already do.
Workaround: pin the digest manually, or clear the datasource-docker-hub-cache entry for the image.
For the fix, dropping the cache shortcut is simpler than adding a freshness check, because a tag can move at any time and there's no safe cache age to pick. The cost is one HEAD request per digest lookup on Docker Hub.
Source: renovatebot/renovate