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
- Ensure the directory containing `filename` (tmpDir) exists and is writable by the process (create it before calling WriteBinary)
- Check free disk space and remove stale `<filename>.tmp` files from crashed runs
- Fix filesystem permissions or move the cache path to a writable volume
- 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
- Create and permission the index-header cache directory at startup, not lazily
- Monitor disk usage on the store gateway cache volume
- Clean up stale .tmp files from crashed writers before restarting
- Run the process with a dedicated user owning the cache directory
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)