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

  1. Wait for the rate window to reset and retry; the check is transient by nature.
  2. 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.
  3. Reduce update-check frequency or the number of watched images.
  4. 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

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


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)