thanos-io/thanos · error

write index header

Error message

write index header

What it means

NewLazyBinaryReader wraps errors from WriteBinary when the index-header file is missing on disk and must be (re)built from the object store. It means Thanos could not produce or persist the index-header — download failure, object not found, or local write failure.

Solutions

  1. Check object storage connectivity and credentials (try listing/downloading the block manually)
  2. Verify the block still exists in the bucket (it may have been deleted/compacted away)
  3. Ensure the local cache directory is writable
  4. Retry — transient network failures are common; Thanos will rebuild the index-header on next attempt
Defensive patterns

Strategy: retry

Validate before calling

if _, err := bkt.Exists(ctx, filepath.Join(id.String(), block.IndexFilename)); err != nil { /* block missing in bucket; don't attempt lazy download */ }

Try / catch

r, err := indexheader.NewLazyBinaryReader(...)
if err != nil && strings.Contains(err.Error(), "write index header") { retry with backoff; verify bucket creds and disk space }

Prevention

When it happens

Trigger: Index-header missing locally and lazyDownload=true (or non-lazy path after stat shows not-exist): WriteBinary(ctx, bkt, id, ...) fails because the object-store download errors, the block doesn't exist in the bucket, or the local file write fails.

Common situations: Block deleted from bucket while still referenced; expired/insufficient object-storage credentials; network outage to the bucket; read-only cache directory preventing the write.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at pkg/block/indexheader/lazy_binary_reader.go:120

	postingOffsetsInMemSampling int,
	metrics *LazyBinaryReaderMetrics,
	binaryReaderMetrics *BinaryReaderMetrics,
	onClosed func(*LazyBinaryReader),
	lazyDownload bool,
) (*LazyBinaryReader, error) {
	if dir != "" && !lazyDownload {
		indexHeaderFile := filepath.Join(dir, id.String(), block.IndexHeaderFilename)
		// If the index-header doesn't exist we should download it.
		if _, err := os.Stat(indexHeaderFile); err != nil {
			if !os.IsNotExist(err) {
				return nil, errors.Wrap(err, "read index header")
			}

			level.Debug(logger).Log("msg", "the index-header doesn't exist on disk; recreating", "path", indexHeaderFile)

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

			level.Debug(logger).Log("msg", "built index-header file", "path", indexHeaderFile, "elapsed", time.Since(start))
		}
	}

	return &LazyBinaryReader{
		ctx:                         ctx,
		logger:                      logger,
		bkt:                         bkt,
		dir:                         dir,
		id:                          id,
		postingOffsetsInMemSampling: postingOffsetsInMemSampling,
		metrics:                     metrics,
		binaryReaderMetrics:         binaryReaderMetrics,
		usedAt:                      atomic.NewInt64(time.Now().UnixNano()),
		onClosed:                    onClosed,
		lazyDownload:                lazyDownload,

View on GitHub (pinned to 35b8b99117)