thanos-io/thanos · error
read index header
Error message
read index header
What it means
NewLazyBinaryReader wraps os.Stat errors (other than not-exist) when checking for the index-header file with 'read index header'. The file's existence cannot even be determined — a filesystem/permission problem, not a missing file.
Solutions
- Fix permissions on the block cache directory (chmod/chown so the Thanos process can stat files)
- Verify the configured --store.index-cache / data directory path is correct and mounted
- Check disk health and mount status in the container/host
- If the directory is wrong, correct the configuration and restart
Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(filepath.Join(dir, id.String(), block.IndexHeaderFilename)); err != nil && !os.IsNotExist(err) { /* fix fs permissions/mount before constructing reader */ } Try / catch
r, err := indexheader.NewLazyBinaryReader(...); if err != nil && strings.Contains(err.Error(), "read index header") { check dir permissions; fail fast with actionable message } Prevention
- Run the process with read access to the data directory
- Verify volume mounts in containers start correctly
- Alert on EACCES/EBUSY from the cache directory
When it happens
Trigger: NewLazyBinaryReader(dir, id, ..., lazyDownload=false) where os.Stat on <dir>/<block-id>/index-header fails with permission or I/O errors (not IsNotExist).
Common situations: Wrong data directory configured; read-only or damaged local disk; permission changes on the cache directory; container volume mount issues.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- add index meta
- create meta fetcher
- create working compact directory
- create working downsample directory
- create dir
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/4d25eb9c9077fbbb.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/block/indexheader/lazy_binary_reader.go:113
// (mmap) the index-header; it will be loaded at first Reader function call.
func NewLazyBinaryReader(
ctx context.Context,
logger log.Logger,
bkt objstore.BucketReader,
dir string,
id ulid.ULID,
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,View on GitHub (pinned to 35b8b99117)