{"record":{"id":"9fbdf630ab6ad6ba","repo":"thanos-io/thanos","slug":"get-range-reader","errorCode":null,"errorMessage":"get range reader","messagePattern":"get range reader","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/bucket.go","lineNumber":2512,"sourceCode":"\n\t// Get object handles for all chunk files from storage.\n\tif err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error {\n\t\tb.chunkObjs = append(b.chunkObjs, n)\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, errors.Wrap(err, \"list chunk files\")\n\t}\n\treturn b, nil\n}\n\nfunc (b *bucketBlock) indexFilename() string {\n\treturn path.Join(b.meta.ULID.String(), block.IndexFilename)\n}\n\nfunc (b *bucketBlock) readIndexRange(ctx context.Context, off, length int64, logger log.Logger) ([]byte, error) {\n\tr, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"get range reader\")\n\t}\n\tdefer runutil.CloseWithLogOnErr(logger, r, \"readIndexRange close range reader\")\n\n\t// Preallocate the buffer with the exact size so we don't waste allocations\n\t// while progressively growing an initial small buffer. The buffer capacity\n\t// is increased by MinRead to avoid extra allocations due to how ReadFrom()\n\t// internally works.\n\tbuf := bytes.NewBuffer(make([]byte, 0, length+bytes.MinRead))\n\tif _, err := buf.ReadFrom(r); err != nil {\n\t\treturn nil, errors.Wrap(err, \"read range\")\n\t}\n\treturn buf.Bytes(), nil\n}\n\nfunc (b *bucketBlock) readChunkRange(ctx context.Context, seq int, off, length int64, chunkRanges byteRanges, logger log.Logger) (*[]byte, error) {\n\tif seq < 0 || seq >= len(b.chunkObjs) {\n\t\treturn nil, errors.Errorf(\"unknown segment file for index %d\", seq)\n\t}","sourceCodeStart":2494,"sourceCodeEnd":2530,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/bucket.go#L2494-L2530","documentation":"readIndexRange fetches a byte range of the block index file from object storage via bkt.GetRange. Any failure obtaining the range reader (permissions, missing object, network error) is wrapped as \"get range reader\".","triggerScenarios":"bkt.GetRange on <ULID>/index fails during index-header-based postings lookups: the block index was deleted (compaction race), credentials lack read access, or the storage backend returned an error.","commonSituations":"Blocks compacted/deleted from the bucket while store gateway still lists them; IAM changes removing GetObject; transient network/5xx errors against S3/GCS; clock-skew or signature errors with presigned access.","solutions":["Check the wrapped provider error: 404 means the block index is gone — resync blocks (thanos tools bucket verify or restart to refresh the metastore)","Verify credentials allow GetObject on the bucket/prefix","Retry on transient 5xx/network errors; store gateways retry internally but large outages surface this","Ensure block deletion/compaction is coordinated with store gateway block sync"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure the block index exists before ranging\nif ok, err := bkt.Exists(ctx, path.Join(meta.ULID.String(), block.IndexFilename)); err != nil || !ok { resyncBlocks() }","typeGuard":null,"tryCatchPattern":"r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)\nif err != nil {\n    return nil, errors.Wrap(err, \"get range reader\")\n}","preventionTips":["Keep block sync (metastore/index cache) fresh so deleted blocks are dropped promptly","Ensure GetObject permission on the bucket","Handle 404 by triggering a block resync rather than repeated retries"],"tags":["object-storage","s3","network"],"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"}