thanos-io/thanos · error
read range
Error message
read range
What it means
This error wraps any failure that occurs while reading an object-storage byte range into an in-memory buffer inside bucketBlock.readAllChunks/readChunkRange helper. The store gateway fetched a range (e.g. a chunk file segment) via bkt.GetRange and then buffered it with bytes.Buffer.ReadFrom; if the underlying reader (S3/GCS/Azure/etc.) returns any I/O error mid-stream, it is wrapped with the message 'read range'. It is a transport-level failure, not a data-format problem.
Solutions
- Inspect the wrapped inner error to identify the object-store client failure and fix root cause (credentials, bucket, endpoint).
- Increase object-store client timeout/retry config in the bucket store config (http-client, retries on 5xx).
- Verify network path to object storage (VPC endpoints, proxies, DNS) from the store-gateway pods.
- Retry the query; Thanos retries bucket requests automatically a few times, transient errors often resolve.
Example fix
// before
buf := bytes.NewBuffer(make([]byte, 0, length+bytes.MinRead))
if _, err := buf.ReadFrom(r); err != nil {
return nil, errors.Wrap(err, "read range")
}
// after (caller side: bound the request with a context and let retries happen)
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
reader, err := b.bkt.GetRange(ctx, obj, off, length)
if err != nil {
return nil, errors.Wrap(err, "get range reader")
} Defensive patterns
Strategy: retry
Validate before calling
// ensure reader/context are bounded before use
if r == nil { return errors.New("nil range reader") }
if _, ok := ctx.Deadline(); !ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
} Try / catch
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry with backoff
}
return errors.Wrap(err, "read range")
} Prevention
- Configure object-store client timeouts and retry limits in bucket store config
- Monitor S3/GCS 5xx and throttling metrics
- Keep store-gateway close to object storage (same region/VPC endpoint)
When it happens
Trigger: bucketBlock.readChunkRange/readAllChunks calls buf.ReadFrom(r) on a range reader from bkt.GetRange and the object store read fails mid-stream (connection reset, timeout, 5xx retried exhausted, truncated body).
Common situations: Object storage flakiness (S3 503 slow-down, GCS resets), network partitions between store-gateway and bucket, proxy/LB idle timeouts cutting long chunk downloads, over-aggressive object-store client timeouts.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- read meta file
- get header from object storage of
- read file
- sync before first pass of downsampling
- sync before second pass of downsampling
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/5ab2db5ae46f6029.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/bucket.go:2522
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)
}
// Get a reader for the required range.
reader, err := b.bkt.GetRange(ctx, b.chunkObjs[seq], off, length)
if err != nil {
return nil, errors.Wrap(err, "get range reader")
}
defer runutil.CloseWithLogOnErr(logger, reader, "readChunkRange close range reader")
// Get a buffer from the pool.
chunkBuffer, err := b.chunkPool.Get(chunkRanges.size())View on GitHub (pinned to 35b8b99117)