thanos-io/thanos · error

write index header

Error message

write index header

What it means

When loading an index-header, WriteBinaryToDisk-style logic first tries to read the existing index-header file from disk; if that fails it logs a debug message and regenerates it via WriteBinary (downloading index-header info from the bucket). This error wraps any failure of that regeneration step, so the root cause is inside WriteBinary (bucket download, size-limit error, file creation error, etc.).

Solutions

  1. Inspect the wrapped (cause) error: if it's a download/object error, verify object-store credentials, endpoint, and that the block's index files exist in the bucket.
  2. If the cache file was corrupt, delete the cache file and retry — it will be regenerated.
  3. Check free disk space and permissions on the cache directory.
  4. Retry the store gateway query; transient bucket errors are often temporary.

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

// ensure cache dir usable before attempting regeneration
if err := os.MkdirAll(cacheDir, 0o755); err != nil {
    return fmt.Errorf("cache dir unusable: %w", err)
}
if fi, err := os.Stat(cachePath); err == nil && fi.Size() == 0 {
    os.Remove(cachePath)
}

Type guard

null

Try / catch

b, err := WriteBinaryToDisk(ctx, bkt, id, cachePath, metrics.DownloadDuration)
var netErr net.Error
if err != nil && errors.As(err, &netErr) {
    return retry.WithBackoff(ctx, func() error {
        _, err = WriteBinaryToDisk(ctx, bkt, id, cachePath, metrics.DownloadDuration)
        return err
    })
}

Prevention

When it happens

Trigger: NewBinaryReader/LoadBinaryReader path with a cache filename: the cached .index-header file is missing/corrupt on disk, then WriteBinary fails — e.g., bucket download error, object not found, 64GiB size limit hit, or permission failure creating the cache file.

Common situations: Object store outage or wrong credentials causing the index download to fail; corrupted cached index-header being recreated; disk full when writing the regenerated cache file.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

	postingOffsetsInMemSampling int

	metrics *BinaryReaderMetrics
}

// NewBinaryReader loads or builds new index-header if not present on disk.
func NewBinaryReader(ctx context.Context, logger log.Logger, bkt objstore.BucketReader, dir string, id ulid.ULID, postingOffsetsInMemSampling int, metrics *BinaryReaderMetrics) (*BinaryReader, error) {
	if dir != "" {
		binfn := filepath.Join(dir, id.String(), block.IndexHeaderFilename)
		br, err := newFileBinaryReader(binfn, postingOffsetsInMemSampling, metrics)
		if err == nil {
			return br, nil
		}

		level.Debug(logger).Log("msg", "failed to read index-header from disk; recreating", "path", binfn, "err", err)

		start := time.Now()
		if _, err := WriteBinary(ctx, bkt, id, binfn, metrics.downloadDuration); err != nil {
			return nil, errors.Wrap(err, "write index header")
		}

		level.Debug(logger).Log("msg", "built index-header file", "path", binfn, "elapsed", time.Since(start))
		return newFileBinaryReader(binfn, postingOffsetsInMemSampling, metrics)
	} else {
		buf, err := WriteBinary(ctx, bkt, id, "", metrics.downloadDuration)
		if err != nil {
			return nil, errors.Wrap(err, "generate index header")
		}

		return newMemoryBinaryReader(buf, postingOffsetsInMemSampling, metrics)
	}
}

func newMemoryBinaryReader(buf []byte, postingOffsetsInMemSampling int, metrics *BinaryReaderMetrics) (bw *BinaryReader, err error) {
	r := &BinaryReader{
		b:                           realByteSlice(buf),
		c:                           nil,

View on GitHub (pinned to 35b8b99117)