thanos-io/thanos · error

calculate hash

Error message

calculate hash %v

What it means

GatherFileStats computes a content hash for each non-directory chunk file using metadata.CalculateHash and wraps its failure with this message. This means reading + hashing (hashfunc over the file contents) of one chunk file failed — usually an I/O error while reading the chunk.

Solutions

  1. Re-read the specific chunk file manually to confirm it's readable (cat/sha256sum the file).
  2. Prevent concurrent modification: ensure the block is not deleted/compacted during upload.
  3. Check disk health (dmesg, SMART) if I/O errors repeat on the same file.
  4. Retry the upload; transient I/O issues may clear.

Example fix

// before
h, err := metadata.CalculateHash(filepath.Join(blockDir, ChunksDirname, f.Name()), hf, logger)
if err != nil {
	return nil, errors.Wrapf(err, "calculate hash %v", filepath.Join(ChunksDirname, f.Name()))
}
// after
h, err := metadata.CalculateHash(filepath.Join(blockDir, ChunksDirname, f.Name()), hf, logger)
if err != nil {
	return nil, errors.Wrapf(err, "calculate hash %v", filepath.Join(ChunksDirname, f.Name()))
}
// caller side: retry GatherFileStats before failing the whole upload
Defensive patterns

Strategy: retry

Validate before calling

for _, name := range chunkNames {
	f, err := os.Open(filepath.Join(blockDir, "chunks", name))
	if err != nil { return fmt.Errorf("chunk %s unreadable: %w", name, err) }
	f.Close()
}

Try / catch

if err := retryWithBackoff(ctx, 3, time.Second, func() error {
	_, err := block.GatherFileStats(blockDir, hashFunc, logger)
	return err
}); err != nil {
	return fmt.Errorf("hashing block %s failed after retries: %w", blockDir, err)
}

Prevention

When it happens

Trigger: metadata.CalculateHash on <blockDir>/chunks/<file> returned an error — the file disappeared or became unreadable during hashing, disk I/O error, or the provided hash function (e.g., SHA256) hit a read failure on a large/sparse file.

Common situations: Block deleted concurrently by compaction/retention while being uploaded; failing disk sector on a specific chunk; NFS timeouts while reading large chunk segments.

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


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

Appendix: source

Thrown at pkg/block/block.go:345

func GatherFileStats(blockDir string, hf metadata.HashFunc, logger log.Logger) (res []metadata.File, _ error) {
	files, err := os.ReadDir(filepath.Join(blockDir, ChunksDirname))
	if err != nil {
		return nil, errors.Wrapf(err, "read dir %v", filepath.Join(blockDir, ChunksDirname))
	}
	for _, f := range files {
		fi, err := f.Info()
		if err != nil {
			return nil, errors.Wrapf(err, "getting file info %v", filepath.Join(ChunksDirname, f.Name()))
		}

		mf := metadata.File{
			RelPath:   filepath.Join(ChunksDirname, f.Name()),
			SizeBytes: fi.Size(),
		}
		if hf != metadata.NoneFunc && !f.IsDir() {
			h, err := metadata.CalculateHash(filepath.Join(blockDir, ChunksDirname, f.Name()), hf, logger)
			if err != nil {
				return nil, errors.Wrapf(err, "calculate hash %v", filepath.Join(ChunksDirname, f.Name()))
			}
			mf.Hash = &h
		}
		res = append(res, mf)
	}

	indexFile, err := os.Stat(filepath.Join(blockDir, IndexFilename))
	if err != nil {
		return nil, errors.Wrapf(err, "stat %v", filepath.Join(blockDir, IndexFilename))
	}
	mf := metadata.File{
		RelPath:   indexFile.Name(),
		SizeBytes: indexFile.Size(),
	}
	if hf != metadata.NoneFunc {
		h, err := metadata.CalculateHash(filepath.Join(blockDir, IndexFilename), hf, logger)
		if err != nil {
			return nil, errors.Wrapf(err, "calculate hash %v", indexFile.Name())

View on GitHub (pinned to 35b8b99117)