thanos-io/thanos · error
add index meta
Error message
add index meta
What it means
WriteBinary serializes an index-header file for a TSDB block. The first serialization step is bw.AddIndexMeta(indexVersion, ir.toc.PostingsTable), which writes the index version and postings-table offset into the buffered writer. This error wraps any failure returned by that call, most commonly an underlying write/flush error from the bufio.Writer backing the binary writer (e.g. disk full, I/O error) or an unsupported index version.
Solutions
- Check free disk space on the volume holding the block directory (df -h) and clean up if full.
- Verify write permissions on the directory containing the index-header temp file (<filename>.tmp).
- Check dmesg / filesystem health for underlying I/O errors on the disk.
- Re-download or re-upload the block's index file if the source index is corrupted (invalid version/TOC).
- Retry WriteBinary; transient I/O failures on network-backed storage can clear on retry.
Example fix
// before: no preflight space/permission check, error surfaces only here
bw, err := newBinaryWriter(id, tmpFilename, buf)
...
// after: fail early with a clear message
if err := checkWritable(tmpFilename); err != nil {
return nil, errors.Wrapf(err, "index-header dir %s not writable", filepath.Dir(tmpFilename))
} Defensive patterns
Strategy: validation
Validate before calling
// Go: preflight writable temp dir with enough space before WriteBinary
func canWriteIndexHeader(dir string) error {
info, err := os.Stat(dir)
if err != nil { return err }
if !info.IsDir() { return fmt.Errorf("%s is not a directory", dir) }
probe := filepath.Join(dir, ".write-probe")
if err := os.WriteFile(probe, []byte("x"), 0o644); err != nil { return err }
return os.Remove(probe)
} Try / catch
// Go
ir, err := indexheader.WriteBinary(ctx, bkt, id, dst)
if err != nil {
if strings.Contains(err.Error(), "add index meta") {
// disk/permission problem writing the index-header temp file
log.Error("index-header build failed at AddIndexMeta; check disk space/permissions", "err", err)
}
return err
} Prevention
- Monitor disk usage on store-gateway/compactor data volumes and alert before 90% full.
- Run Thanos containers with a dedicated writable volume and correct fsGroup/runAsUser.
- Delete stale .tmp index-header files during restart cleanup.
- Watch kernel logs for early signs of storage device failure.
When it happens
Trigger: Calling WriteBinary (directly or via NewBinaryReader / NewLazyBinaryReader) on a block whose on-disk or in-memory index write fails during the very first write to the bufio.Writer: AddIndexMeta writes the magic/version/postings-offset and the buffered writer's first flush to the underlying file or buffer fails (disk full, EIO, permission issue on the temp file).
Common situations: Store Gateway or Compactor rebuilding an index-header on a disk that is full or failing; writing into a directory without write permission (the .tmp temp file); a corrupted or unsupported index version being passed through.
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/2de1b1018b055e8e.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/block/indexheader/binary_reader.go:134
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
}
if err := bw.writer.Flush(); err != nil {
return nil, errors.Wrap(err, "flush")
}
View on GitHub (pinned to 35b8b99117)