thanos-io/thanos · error
no more data left in subrange at position
Error message
no more data left in subrange at position %d, subrange length %d, reading position %d
What it means
Raised by subrangesReader.Read when the current subrange is shorter than subrangeSize and the reader is asked to read past the data actually stored in that subrange. It indicates an internal inconsistency: the reader believed more bytes were available (c.remaining) than the subrange actually holds. The comment in the source says this 'can only happen if subrange's length is not subrangeSize'.
Solutions
- Check the cache backend's maximum value size; truncated entries are the usual culprit
- Flush/invalidate the affected cache entries and retry the read
- Ensure all Thanos components use the same subrangeSize configuration
- Confirm the reader is single-use and not advanced concurrently by multiple goroutines
- Bump to a newer Thanos version where subrange length accounting was fixed
Example fix
// before
cacheConfig:
type: MEMCACHED
memcached:
max_item_size: 1MiB # entries silently truncated
// after
cacheConfig:
type: MEMCACHED
memcached:
max_item_size: 16MiB # >= max subrange/object chunk size Defensive patterns
Strategy: validation
Validate before calling
if cacheBackend == "MEMCACHED" && subrangeOrChunkSize > maxItemSize { return errors.New("subrange exceeds cache max item size; entries will truncate") } Try / catch
if _, err := reader.Read(buf); err != nil {
if strings.Contains(err.Error(), "no more data left in subrange") {
// invalidate the cached entry and re-fetch from object store
}
} Prevention
- Set cache max_item_size >= subrange/object chunk size
- Use identical subrangeSize across all Thanos instances
- Flush stale entries after upgrading Thanos
- Watch for silent value truncation in memcached/redis
When it happens
Trigger: Calling Read when len(currentSubrange) - offsetInSubrange <= 0, i.e. the stored subrange is truncated/shorter than subrangeSize while remaining bytes were still promised to the caller.
Common situations: Corrupted or partially written cache entries, cache backends that truncate large values (memcached/redis size limits), or reading an object whose cached chunks were stored by a different Thanos version with different subrange sizing.
Related errors
- read position
- subrange for offset not found
- 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/a58ec3be49d055ba.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/cache/caching_bucket.go:543
}
}
func (c *subrangesReader) Read(p []byte) (n int, err error) {
if c.remaining <= 0 {
return 0, io.EOF
}
currentSubrangeOffset := (c.readOffset / c.subrangeSize) * c.subrangeSize
currentSubrange, err := c.subrangeAt(currentSubrangeOffset)
if err != nil {
return 0, errors.Wrapf(err, "read position: %d", c.readOffset)
}
offsetInSubrange := int(c.readOffset - currentSubrangeOffset)
toCopy := len(currentSubrange) - offsetInSubrange
if toCopy <= 0 {
// This can only happen if subrange's length is not subrangeSize, and reader is told to read more data.
return 0, errors.Errorf("no more data left in subrange at position %d, subrange length %d, reading position %d", currentSubrangeOffset, len(currentSubrange), c.readOffset)
}
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]]View on GitHub (pinned to 35b8b99117)