{"record":{"id":"a58ec3be49d055ba","repo":"thanos-io/thanos","slug":"no-more-data-left-in-subrange-at-position-d-subr","errorCode":null,"errorMessage":"no more data left in subrange at position %d, subrange length %d, reading position %d","messagePattern":"no more data left in subrange at position (.+?), subrange length (.+?), reading position (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/cache/caching_bucket.go","lineNumber":543,"sourceCode":"\t}\n}\n\nfunc (c *subrangesReader) Read(p []byte) (n int, err error) {\n\tif c.remaining <= 0 {\n\t\treturn 0, io.EOF\n\t}\n\n\tcurrentSubrangeOffset := (c.readOffset / c.subrangeSize) * c.subrangeSize\n\tcurrentSubrange, err := c.subrangeAt(currentSubrangeOffset)\n\tif err != nil {\n\t\treturn 0, errors.Wrapf(err, \"read position: %d\", c.readOffset)\n\t}\n\n\toffsetInSubrange := int(c.readOffset - currentSubrangeOffset)\n\ttoCopy := len(currentSubrange) - offsetInSubrange\n\tif toCopy <= 0 {\n\t\t// This can only happen if subrange's length is not subrangeSize, and reader is told to read more data.\n\t\treturn 0, errors.Errorf(\"no more data left in subrange at position %d, subrange length %d, reading position %d\", currentSubrangeOffset, len(currentSubrange), c.readOffset)\n\t}\n\n\tif len(p) < toCopy {\n\t\ttoCopy = len(p)\n\t}\n\tif c.remaining < int64(toCopy) {\n\t\ttoCopy = int(c.remaining) // Conversion is safe, c.remaining is small enough.\n\t}\n\n\tcopy(p, currentSubrange[offsetInSubrange:offsetInSubrange+toCopy])\n\tc.readOffset += int64(toCopy)\n\tc.remaining -= int64(toCopy)\n\n\treturn toCopy, nil\n}\n\nfunc (c *subrangesReader) subrangeAt(offset int64) ([]byte, error) {\n\tb := c.subranges[c.offsetsKeys[offset]]","sourceCodeStart":525,"sourceCodeEnd":561,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/cache/caching_bucket.go#L525-L561","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncacheConfig:\n  type: MEMCACHED\n  memcached:\n    max_item_size: 1MiB   # entries silently truncated\n// after\ncacheConfig:\n  type: MEMCACHED\n  memcached:\n    max_item_size: 16MiB  # >= max subrange/object chunk size","handlingStrategy":"validation","validationCode":"if cacheBackend == \"MEMCACHED\" && subrangeOrChunkSize > maxItemSize { return errors.New(\"subrange exceeds cache max item size; entries will truncate\") }","typeGuard":null,"tryCatchPattern":"if _, err := reader.Read(buf); err != nil {\n    if strings.Contains(err.Error(), \"no more data left in subrange\") {\n        // invalidate the cached entry and re-fetch from object store\n    }\n}","preventionTips":["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"],"tags":["go","cache","thanos","truncated-data"],"backgroundTag":"index-out-of-bounds","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}