thanos-io/thanos · error

new index reader

Error message

new index reader

What it means

Thanos' indexheader.WriteBinary converts a block's index postings into a compact binary index-header file. This error wraps failure to create the chunked index reader over the block's index (via newChunkedIndexReader), i.e. the source index could not be opened/parsed to build the binary header.

Solutions

  1. Verify the block ID and that index.bin exists and is fully uploaded in the bucket (check meta.json and the block directory)
  2. Check object storage credentials/permissions for the bucket used to fetch the index
  3. Re-download or re-sync the block from a healthy replica if index.bin is truncated
  4. Ensure the block was produced by a supported Prometheus/Thanos index version

Example fix

// before
if err := indexheader.WriteBinary(ctx, bkt, id, filename); err != nil {
	return err
}
// after
ok, err := block.Exists(ctx, bkt, id)
if err != nil { return err }
if !ok { return errors.Errorf("block %s does not exist", id) }
if err := block.DownloadIndex(ctx, logger, bkt, id, dir); err != nil {
	return errors.Wrap(err, "download index")
}
if err := indexheader.WriteBinary(ctx, bkt, id, filename); err != nil {
	return errors.Wrap(err, "write index header")
}
Defensive patterns

Strategy: fallback

Validate before calling

ok, err := block.Exists(ctx, bkt, id)
if err != nil { return err }
if !ok { return errors.Errorf("block %s not found in bucket", id) }
if _, err := bkt.Get(ctx, path.Join(id.String(), block.IndexFilename)); err != nil {
	return errors.Wrap(err, "index.bin not fetchable")
}

Type guard

func indexAvailable(ctx context.Context, bkt objstore.Bucket, id ulid.ULID) bool {
	rc, err := bkt.Get(ctx, path.Join(id.String(), block.IndexFilename))
	if err != nil { return false }
	defer rc.Close()
	return true
}

Try / catch

hdr, err := indexheader.NewBinaryReader(ctx, logger, bkt, dir, id, cfg)
if err != nil {
	if objstore.IsNotFoundError(errors.Cause(err)) {
		// block gone: refresh meta or remove from local cache and continue
	}
	return errors.Wrapf(err, "build index header for %s", id)
}

Prevention

When it happens

Trigger: WriteBinary(ctx, bkt, id, filename) is called (directly or via NewBinaryReader/NewLazyBinaryReader) and newChunkedIndexReader fails: the block's index.bin is missing from the bucket or tmp dir, not downloadable, or its format/version cannot be parsed.

Common situations: Store gateway building an index-header cache for a block whose index.bin was deleted or still uploading; misconfigured bucket credentials/block ID causing fetch failures; index built by an unsupported Prometheus version.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at pkg/block/indexheader/binary_reader.go:117

	// PostingsOffsetTable holds start to the same Postings Offset Table section as index related to this index header.
	PostingsOffsetTable uint64
}

// WriteBinary build index header from the pieces of index in object storage, and cached in file if necessary.
func WriteBinary(ctx context.Context, bkt objstore.BucketReader, id ulid.ULID, filename string, downloadDuration prometheus.Histogram) ([]byte, error) {
	start := time.Now()

	defer func() {
		downloadDuration.Observe(time.Since(start).Seconds())
	}()
	var tmpDir = ""
	if filename != "" {
		tmpDir = filepath.Dir(filename)
	}
	parallelBucket := WrapWithParallel(bkt, tmpDir)
	ir, indexVersion, err := newChunkedIndexReader(ctx, parallelBucket, id)
	if err != nil {
		return nil, errors.Wrap(err, "new index reader")
	}
	tmpFilename := ""
	if filename != "" {
		tmpFilename = filename + ".tmp"
	}

	// Buffer for copying and encbuffers.
	// This also will control the size of file writer buffer.
	buf := make([]byte, 32*1024)
	bw, err := newBinaryWriter(id, tmpFilename, buf)
	if err != nil {
		return nil, errors.Wrap(err, "new binary index header writer")
	}
	defer runutil.CloseWithErrCapture(&err, bw, "close binary writer for %s", tmpFilename)

	if err := bw.AddIndexMeta(indexVersion, ir.toc.PostingsTable); err != nil {
		return nil, errors.Wrap(err, "add index meta")
	}

View on GitHub (pinned to 35b8b99117)