thanos-io/thanos · error

get range reader

Error message

get range reader

What it means

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".

Solutions

  1. Check the wrapped provider error: 404 means the block index is gone — resync blocks (thanos tools bucket verify or restart to refresh the metastore)
  2. Verify credentials allow GetObject on the bucket/prefix
  3. Retry on transient 5xx/network errors; store gateways retry internally but large outages surface this
  4. Ensure block deletion/compaction is coordinated with store gateway block sync
Defensive patterns

Strategy: retry

Validate before calling

// ensure the block index exists before ranging
if ok, err := bkt.Exists(ctx, path.Join(meta.ULID.String(), block.IndexFilename)); err != nil || !ok { resyncBlocks() }

Try / catch

r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)
if err != nil {
    return nil, errors.Wrap(err, "get range reader")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/9fbdf630ab6ad6ba. Report an issue: GitHub.

Appendix: source

Thrown at pkg/store/bucket.go:2512

	// Get object handles for all chunk files from storage.
	if err = bkt.Iter(ctx, path.Join(meta.ULID.String(), block.ChunksDirname), func(n string) error {
		b.chunkObjs = append(b.chunkObjs, n)
		return nil
	}); err != nil {
		return nil, errors.Wrap(err, "list chunk files")
	}
	return b, nil
}

func (b *bucketBlock) indexFilename() string {
	return path.Join(b.meta.ULID.String(), block.IndexFilename)
}

func (b *bucketBlock) readIndexRange(ctx context.Context, off, length int64, logger log.Logger) ([]byte, error) {
	r, err := b.bkt.GetRange(ctx, b.indexFilename(), off, length)
	if err != nil {
		return nil, errors.Wrap(err, "get range reader")
	}
	defer runutil.CloseWithLogOnErr(logger, r, "readIndexRange close range reader")

	// Preallocate the buffer with the exact size so we don't waste allocations
	// while progressively growing an initial small buffer. The buffer capacity
	// is increased by MinRead to avoid extra allocations due to how ReadFrom()
	// internally works.
	buf := bytes.NewBuffer(make([]byte, 0, length+bytes.MinRead))
	if _, err := buf.ReadFrom(r); err != nil {
		return nil, errors.Wrap(err, "read range")
	}
	return buf.Bytes(), nil
}

func (b *bucketBlock) readChunkRange(ctx context.Context, seq int, off, length int64, chunkRanges byteRanges, logger log.Logger) (*[]byte, error) {
	if seq < 0 || seq >= len(b.chunkObjs) {
		return nil, errors.Errorf("unknown segment file for index %d", seq)
	}

View on GitHub (pinned to 35b8b99117)