containerd/containerd · warning · errdefs.ErrNotFound

referrers index size %d exceeds maximum allowed %d: %w

Error message

referrers index size %d exceeds maximum allowed %d: %w

What it means

FetchReferrers enforces MaxManifestSize on the referrers index before decoding; if the reported content length exceeds the limit, it fails, wrapping errdefs.ErrNotFound. This bounds memory usage and treats oversized/abnormal referrers indexes as effectively absent. The '%w' verb with ErrNotFound means callers may treat it as 'no referrers found'.

Source

Thrown at core/remotes/docker/referrers.go:51

)

func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, opts ...remotes.FetchReferrersOpt) ([]ocispec.Descriptor, error) {
	var config remotes.FetchReferrersConfig
	for _, opt := range opts {
		opt(ctx, &config)
	}
	rc, size, err := r.openReferrers(ctx, dgst, config)
	if err != nil {
		if errdefs.IsNotFound(err) {
			return []ocispec.Descriptor{}, nil
		}
		return nil, err
	}
	defer rc.Close()
	if size < 0 {
		size = MaxManifestSize
	} else if size > MaxManifestSize {
		return nil, fmt.Errorf("referrers index size %d exceeds maximum allowed %d: %w", size, MaxManifestSize, errdefs.ErrNotFound)
	}

	var index ocispec.Index
	dec := json.NewDecoder(io.LimitReader(rc, size))
	if err := dec.Decode(&index); err != nil {
		return nil, fmt.Errorf("failed to decode referrers index: %w", err)
	}
	if _, err := dec.Token(); !errors.Is(err, io.EOF) {
		return nil, fmt.Errorf("unexpected data after JSON object")
	}

	if len(config.ArtifactTypes) == 0 {
		return index.Manifests, nil
	}

	var referrers []ocispec.Descriptor
	tFilter := map[string]struct{}{}
	for _, t := range config.ArtifactTypes {

View on GitHub (pinned to 4246446a2b)

Solutions

  1. Prune/referrer-GC the repository to reduce the referrers index size
  2. Use paged referrers APIs where available instead of fetching the whole index
  3. Increase MaxManifestSize if your deployment truly needs bigger indexes (recompile/config) and accept the memory cost
  4. Treat the wrapped ErrNotFound as 'referrers unavailable' and fall back to scanning manifests

Example fix

// before
referrers, err := fetcher.FetchReferrers(ctx, desc)
// after: tolerate oversized index
referrers, err := fetcher.FetchReferrers(ctx, desc)
if err != nil && errors.Is(err, errdefs.ErrNotFound) {
    referrers = nil // fall back
}
Defensive patterns

Strategy: fallback

Validate before calling

// check referrers index size head-of-time if you control the endpoint
resp, _ := http.Head(referrersURL)
if n := resp.ContentLength; n > 4<<20 { /* avoid full fetch; use paging */ }

Try / catch

referrers, err := fetcher.FetchReferrers(ctx, desc)
if err != nil && errors.Is(err, errdefs.ErrNotFound) {
    referrers = nil // degrade gracefully: treat as no referrers
}

Prevention

When it happens

Trigger: Calling FetchReferrers (or FetchReferrers with filters) against a repository whose referrers index blob Content-Length exceeds MaxManifestSize (typically 4 MiB).

Common situations: A repository with an enormous number of referrer manifests (accumulated signatures/SBOMs) producing a giant tag_schema2/referrers index; a misbehaving registry reporting a bogus large size.

Related errors


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/3f37cb45810cd9de. Report an issue: GitHub.