thanos-io/thanos · error

new binary index header writer

Error message

new binary index header writer

What it means

Immediately after obtaining the chunked index reader, WriteBinary creates a binary writer (newBinaryWriter) for the tmp index-header file. This error wraps failure to create that writer — usually inability to create or open the tmp file for writing on local disk.

Solutions

  1. Ensure the directory containing `filename` (tmpDir) exists and is writable by the process (create it before calling WriteBinary)
  2. Check free disk space and remove stale `<filename>.tmp` files from crashed runs
  3. Fix filesystem permissions or move the cache path to a writable volume
  4. If the cause is an invalid block id, validate id/metadata before calling WriteBinary

Example fix

// before
if err := indexheader.WriteBinary(ctx, bkt, id, filename); err != nil {
	return err
}
// after
if err := os.MkdirAll(filepath.Dir(filename), 0o777); err != nil {
	return errors.Wrap(err, "create index-header dir")
}
if err := indexheader.WriteBinary(ctx, bkt, id, filename); err != nil {
	return errors.Wrap(err, "write index header")
}
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(filename)
if err := os.MkdirAll(dir, 0o777); err != nil { return err }
fi, err := os.Stat(dir)
if err != nil { return err }
if !fi.IsDir() { return errors.Errorf("%s is not a directory", dir) }
if err := unix.Access(dir, unix.W_OK); err != nil {
	return errors.Wrapf(err, "dir %s not writable", dir)
}

Type guard

func writablePath(filename string) error {
	f, err := os.CreateTemp(filepath.Dir(filename), ".wtest")
	if err != nil { return err }
	name := f.Name()
	f.Close()
	return os.Remove(name)
}

Try / catch

if err := indexheader.WriteBinary(ctx, bkt, id, filename); err != nil {
	if errors.Is(errors.Cause(err), os.ErrPermission) || errors.Is(errors.Cause(err), syscall.ENOSPC) {
		// fix permissions/space or fall back to default cache dir, then retry
	}
	return errors.Wrapf(err, "write index header for %s", id)
}

Prevention

When it happens

Trigger: newBinaryWriter(id, tmpFilename, buf) fails during WriteBinary: the directory of `filename` does not exist, filesystem is read-only or full, or permission to create `filename + ".tmp"` is denied. Also fires when id is empty/invalid and the writer validates it.

Common situations: Store gateway configured with a nonexistent or read-only index-header cache directory; volume out of disk space; tmp file left over with bad permissions from a previous crashed run.

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/6dfefece158ce14f. Report an issue: GitHub.

Appendix: source

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

	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")
	}

	if err := ir.CopySymbols(bw.SymbolsWriter(), buf); err != nil {
		return nil, err
	}

	if err := bw.writer.Flush(); err != nil {
		return nil, errors.Wrap(err, "flush")
	}

	if err := ir.CopyPostingsOffsets(bw.PostingOffsetsWriter(), buf); err != nil {
		return nil, err
	}

View on GitHub (pinned to 35b8b99117)