thanos-io/thanos · error

list chunk files

Error message

list chunk files

What it means

When lazy-loading a block, bucketBlockSet/bucketBlock lists all chunk objects under <ULID>/chunks/ in the bucket via bkt.Iter. Failure to enumerate the object storage listing is wrapped as "list chunk files" and prevents loading the block.

Solutions

  1. Verify bucket credentials and that the principal has list permission on the bucket/prefix
  2. Check object-storage availability and rate limits; add backoff/retry
  3. Confirm the bucket and block prefix still exist (block may have been deleted/compacted away)
  4. Inspect the wrapped error for the provider-specific cause (403 vs 5xx vs timeout)
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: ensure list access
it := bkt.Iter(ctx, blockPrefix, func(string) error { return nil })

Try / catch

if err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error {
    b.chunkObjs = append(b.chunkObjs, n)
    return nil
}); err != nil {
    return nil, errors.Wrap(err, "list chunk files")
}

Prevention

When it happens

Trigger: The object store Iter call on the block's chunks directory fails: bucket permission revoked, object storage outage, throttling, or misconfigured bucket credentials.

Common situations: Expired cloud credentials or removed IAM list permission; S3/GCS rate limiting under heavy fan-out; temporary object-storage 5xx; bucket deleted or renamed.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/b51ea7a32ccc6f4d. Report an issue: GitHub.

Appendix: source

Thrown at pkg/store/bucket.go:2500

		estimatedMaxChunkSize:  maxChunkSize,
	}

	// Get object handles for all chunk files (segment files) from meta.json, if available.
	if len(meta.Thanos.SegmentFiles) > 0 {
		b.chunkObjs = make([]string, 0, len(meta.Thanos.SegmentFiles))

		for _, sf := range meta.Thanos.SegmentFiles {
			b.chunkObjs = append(b.chunkObjs, path.Join(meta.ULID.String(), block.ChunksDirname, sf))
		}
		return b, nil
	}

	// Get object handles for all chunk files from storage.
	if err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error {
		b.chunkObjs = append(b.chunkObjs, n)
		return nil
	}); err != nil {
		return nil, errors.Wrap(err, "list chunk files")
	}
	return b, nil
}

func (b *bucketBlock) indexFilename() string {
	return path.Join(b.meta.ULID.String(), block.IndexFilename)
}

func (b *bucketBlock) readIndexRange(ctx context.Context, off, length int64, logger log.Logger) ([]byte, error) {
	r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)
	if err != nil {
		return nil, errors.Wrap(err, "get range reader")
	}
	defer runutil.CloseWithLogOnErr(logger, r, "readIndexRange close range reader")

	// Preallocate the buffer with the exact size so we don't waste allocations
	// while progressively growing an initial small buffer. The buffer capacity
	// is increased by MinRead to avoid extra allocations due to how ReadFrom()

View on GitHub (pinned to 35b8b99117)