thanos-io/thanos · error
get range reader
Error message
get range reader
What it means
readIndexRange fetches a byte range of the block index file from object storage via bkt.GetRange. Any failure obtaining the range reader (permissions, missing object, network error) is wrapped as "get range reader".
Solutions
- Check the wrapped provider error: 404 means the block index is gone — resync blocks (thanos tools bucket verify or restart to refresh the metastore)
- Verify credentials allow GetObject on the bucket/prefix
- Retry on transient 5xx/network errors; store gateways retry internally but large outages surface this
- Ensure block deletion/compaction is coordinated with store gateway block sync
Defensive patterns
Strategy: retry
Validate before calling
// ensure the block index exists before ranging
if ok, err := bkt.Exists(ctx, path.Join(meta.ULID.String(), block.IndexFilename)); err != nil || !ok { resyncBlocks() } Try / catch
r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)
if err != nil {
return nil, errors.Wrap(err, "get range reader")
} Prevention
- Keep block sync (metastore/index cache) fresh so deleted blocks are dropped promptly
- Ensure GetObject permission on the bucket
- Handle 404 by triggering a block resync rather than repeated retries
When it happens
Trigger: bkt.GetRange on <ULID>/index fails during index-header-based postings lookups: the block index was deleted (compaction race), credentials lack read access, or the storage backend returned an error.
Common situations: Blocks compacted/deleted from the bucket while store gateway still lists them; IAM changes removing GetObject; transient network/5xx errors against S3/GCS; clock-skew or signature errors with presigned access.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- check exists
- read postings range
- sync before first pass of downsampling
- sync before second pass of downsampling
- upload file to bucket
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/9fbdf630ab6ad6ba.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/bucket.go:2512
// 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()
// internally works.
buf := bytes.NewBuffer(make([]byte, 0, length+bytes.MinRead))
if _, err := buf.ReadFrom(r); err != nil {
return nil, errors.Wrap(err, "read range")
}
return buf.Bytes(), nil
}
func (b *bucketBlock) readChunkRange(ctx context.Context, seq int, off, length int64, chunkRanges byteRanges, logger log.Logger) (*[]byte, error) {
if seq < 0 || seq >= len(b.chunkObjs) {
return nil, errors.Errorf("unknown segment file for index %d", seq)
}View on GitHub (pinned to 35b8b99117)