thanos-io/thanos · error
read range for seq offset
Error message
read range for seq %d offset %x
What it means
Raised in bucketChunkReader.load when io.ReadFull fails to read the pre-computed byte range for chunk (seq, offset) from the object storage stream. Any error other than an expected ErrUnexpectedEOF on the last chunk is fatal — the fetched range is incomplete or the storage stream broke.
Solutions
- Retry the query to rule out transient object store errors
- Verify range GET support and integrity of the chunks/index files in the bucket
- Increase the fetch window if chunks routinely exceed estimatedMaxChunkSize
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at pkg/store/bucket.go:3785 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/d7b83b76705ac4d5.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/bucket.go:3785
return errors.Wrap(err, "fast forward range reader")
}
readOffset += written
}
// Presume chunk length to be reasonably large for common use cases.
// However, declaration for EstimatedMaxChunkSize warns us some chunks could be larger in some rare cases.
// This is handled further down below.
chunkLen = r.block.estimatedMaxChunkSize
if i+1 < len(pIdxs) {
if diff = pIdxs[i+1].offset - pIdx.offset; int(diff) < chunkLen {
chunkLen = int(diff)
}
}
cb := buf[:chunkLen]
n, err = io.ReadFull(bufReader, cb)
readOffset += n
// Unexpected EOF for last chunk could be a valid case. Any other errors are definitely real.
if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) && i != len(pIdxs)-1 {
return errors.Wrapf(err, "read range for seq %d offset %x", seq, pIdx.offset)
}
chunkDataLen, n := binary.Uvarint(cb)
if n < 1 {
return errors.New("reading chunk length failed")
}
// Chunk length is n (number of bytes used to encode chunk data), 1 for chunk encoding and chunkDataLen for actual chunk data.
// There is also crc32 after the chunk, but we ignore that.
chunkLen = n + 1 + int(chunkDataLen)
if chunkLen <= len(cb) {
c := rawChunk(cb[n:chunkLen])
err = populateChunk(&(res[pIdx.seriesEntry].chks[pIdx.chunk]), &c, aggrs, r.save, calculateChunkChecksum)
if err != nil {
return errors.Wrap(err, "populate chunk")
}
stats.add(ChunksTouched, 1, int(chunkDataLen))
continueView on GitHub (pinned to 35b8b99117)