thanos-io/thanos · error
subrange for offset not found
Error message
subrange for offset %d not found
What it means
subrangeAt looks up a cached subrange by its byte offset in an internal map; if no entry exists for that offset it returns this error. It means the reader's offset-to-key index has no subrange registered at the requested aligned offset, so the requested data cannot be served from cache state.
Solutions
- Verify the read offset is within the object size and the reader was created with the correct range
- Re-fetch the object range to rebuild the reader's subranges
- Check for concurrent eviction of cache entries while the reader is active
- Pin the object range in cache or reduce subrangeSize so all needed subranges fit
- Update Thanos if you suspect a known subrange-index bug
Example fix
// before
offset := int64(10 << 30) // beyond what was fetched into the reader
r.Read(buf)
// after
if offset >= objectSize { return io.EOF }
reader, err := bucketReader.GetRange(ctx, name, offset, length)
if err != nil { return err }
_, err = reader.Read(buf) Defensive patterns
Strategy: try-catch
Validate before calling
if offset < 0 || offset+int64(len(buf)) > objectSize { return io.EOF } Type guard
func offsetInRange(offset int64, size int64) bool { return offset >= 0 && offset < size } Try / catch
n, err := reader.Read(buf)
if err != nil {
if strings.Contains(err.Error(), "subrange for offset") {
// rebuild reader via a fresh GetRange call
reader, err = bucket.GetRange(ctx, name, off, len)
}
} Prevention
- Always create a fresh reader per range request
- Avoid reading past the range requested from the caching bucket
- Pin long-lived readers against concurrent eviction
- Report persistent cases as a Thanos bug with offsets and subrangeSize
When it happens
Trigger: Read computes currentSubrangeOffset := (c.readOffset / c.subrangeSize) * c.subrangeSize and calls subrangeAt, but c.subranges has no entry for that offset key — e.g. the offset is beyond populated subranges or the map was built incompletely.
Common situations: Reading past the populated range of a cached object, cache entries deleted between index build and read, or reusing a reader after its underlying subranges were rebuilt/evicted.
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
- read position
- no more data left in subrange at position
- failed to create inmemory cache
- failed to parse template
- failed to execute template
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/63843adcb6eab0b5.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/cache/caching_bucket.go:563
if len(p) < toCopy {
toCopy = len(p)
}
if c.remaining < int64(toCopy) {
toCopy = int(c.remaining) // Conversion is safe, c.remaining is small enough.
}
copy(p, currentSubrange[offsetInSubrange:offsetInSubrange+toCopy])
c.readOffset += int64(toCopy)
c.remaining -= int64(toCopy)
return toCopy, nil
}
func (c *subrangesReader) subrangeAt(offset int64) ([]byte, error) {
b := c.subranges[c.offsetsKeys[offset]]
if b == nil {
return nil, errors.Errorf("subrange for offset %d not found", offset)
}
return b, nil
}
type getReader struct {
c cache.Cache
ctx context.Context
r io.ReadCloser
buf *bytes.Buffer
startTime time.Time
ttl time.Duration
cacheKey string
maxSize int
}
func (g *getReader) Close() error {
// We don't know if entire object was read, don't store it here.
g.buf = nilView on GitHub (pinned to 35b8b99117)