amir20/dozzle · warning · ErrRateLimited
registry rate limited the request
Error message
registry rate limited the request
What it means
ErrRateLimited means the registry responded with HTTP 429 (TooManyRequests) and asked the client to back off. Dozzle surfaces it as a distinct sentinel so callers can distinguish throttling from real failures.
Solutions
- Wait for the rate window to reset and retry; the check is transient by nature.
- Authenticate to the registry (e.g. Docker Hub paid plan or logged-in token) to raise limits — note Dozzle itself has no credential store, so use a mirror/proxy if needed.
- Reduce update-check frequency or the number of watched images.
- Put a pull-through cache/registry mirror (e.g. a local registry proxy) in front of Docker Hub.
Defensive patterns
Strategy: retry
Type guard
func isRateLimited(err error) bool { return errors.Is(err, imagecheck.ErrRateLimited) } Try / catch
if errors.Is(err, imagecheck.ErrRateLimited) {
// honor Retry-After if present, then retry with exponential backoff
time.Sleep(backoff)
retry()
} Prevention
- Use a registry mirror or pull-through cache for Docker Hub
- Keep update-check intervals modest
- Watch fewer images on rate-limited anonymous access
- Expect 429 bursts on shared/NAT egress IPs
When it happens
Trigger: Digest receives http.StatusTooManyRequests from the registry (registry.go:109), most commonly from Docker Hub's anonymous pull-rate limits when many update checks originate from one IP.
Common situations: Docker Hub's per-IP anonymous rate limit (100 pulls/6h) hit on busy hosts or CI; shared NAT/VPN IPs exhausted of quota; aggressive update-check intervals polling a registry that throttles.
Related errors
- registry requires authentication
- image not found in registry
- cloud rate limited, backing off for
- container not found
- unknown error: with
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/cd63e3b5321c18d5.
Report an issue: GitHub.
Appendix: source
Thrown at internal/imagecheck/registry.go:35
// 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
}
func NewRegistry(timeout time.Duration) *Registry {
return &Registry{View on GitHub (pinned to d9463cbe21)