{"record":{"id":"63843adcb6eab0b5","repo":"thanos-io/thanos","slug":"subrange-for-offset-d-not-found","errorCode":null,"errorMessage":"subrange for offset %d not found","messagePattern":"subrange for offset (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/cache/caching_bucket.go","lineNumber":563,"sourceCode":"\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]]\n\tif b == nil {\n\t\treturn nil, errors.Errorf(\"subrange for offset %d not found\", offset)\n\t}\n\treturn b, nil\n}\n\ntype getReader struct {\n\tc         cache.Cache\n\tctx       context.Context\n\tr         io.ReadCloser\n\tbuf       *bytes.Buffer\n\tstartTime time.Time\n\tttl       time.Duration\n\tcacheKey  string\n\tmaxSize   int\n}\n\nfunc (g *getReader) Close() error {\n\t// We don't know if entire object was read, don't store it here.\n\tg.buf = nil","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/cache/caching_bucket.go#L545-L581","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\noffset := int64(10 << 30) // beyond what was fetched into the reader\nr.Read(buf)\n// after\nif offset >= objectSize { return io.EOF }\nreader, err := bucketReader.GetRange(ctx, name, offset, length)\nif err != nil { return err }\n_, err = reader.Read(buf)","handlingStrategy":"try-catch","validationCode":"if offset < 0 || offset+int64(len(buf)) > objectSize { return io.EOF }","typeGuard":"func offsetInRange(offset int64, size int64) bool { return offset >= 0 && offset < size }","tryCatchPattern":"n, err := reader.Read(buf)\nif err != nil {\n    if strings.Contains(err.Error(), \"subrange for offset\") {\n        // rebuild reader via a fresh GetRange call\n        reader, err = bucket.GetRange(ctx, name, off, len)\n    }\n}","preventionTips":["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"],"tags":["go","cache","thanos","missing-key"],"backgroundTag":"resource-not-found","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"}