thanos-io/thanos · error
read meta from
Error message
read meta from %s
What it means
This error is wrapped around a failure to read a TSDB block's meta.json from the directory the compactor downloaded it into (bdir), during repair of an overlapping/issue-347 block inside Thanos' compact.Group repair flow (compact.go repairBucketBlock). The underlying error comes from metadata.ReadFromDir, which parses and validates meta.json (ULID, time range, compaction level, Thanos version, labels). The wrap preserves the block directory path so operators can locate the corrupted download.
Solutions
- Inspect the block directory in the bucket (thanos tools bucket verify or ls) and check meta.json contents for corruption or missing fields
- Delete or move the broken block out of the bucket so the compactor no longer tries to repair it (only if it is not referenced/needed), then let the compactor resync
- Re-download the block manually (thanos tools bucket download) to rule out transient download corruption and confirm the object in storage itself is intact
- Check the producing side: ensure Prometheus sidecar/uploaded blocks have valid, complete meta.json (upgrade Thanos/Prometheus if very old format)
- If object storage returned partial data consistently, verify bucket permissions and that the bucket is not being concurrently modified by another compactor
Example fix
// before (manual diagnosis of the failing dir) // compactor logs: read meta from /var/thanos/compact/tmp/repair/01ARZ3N... // after: validate the block in the bucket before compaction runs $ thanos tools bucket verify --objstore.config-file=bucket.yaml $ thanos tools bucket inspect --objstore.config-file=bucket.yaml // if meta.json is truly corrupt, remove the broken block: $ thanos tools bucket webhooks... # or manually delete the block ULID dir in the bucket
Defensive patterns
Strategy: validation
Validate before calling
// before running the compactor, verify every block in the bucket parses
err := bucket.Iterate(ctx, "", func(id string) error {
return nil // enumerate block ULIDs first
})
meta, err := metadata.ReadFromDir(blockDir)
if err != nil {
logger.Warn("skipping unreadable block", "dir", blockDir, "err", err)
}
// preflight: thanos tools bucket verify --objstore.config-file=bucket.yaml Prevention
- Run 'thanos tools bucket verify' periodically to catch corrupt meta.json before compaction
- Keep Thanos/Prometheus versions current so uploaded meta.json includes all required fields
- Avoid killing uploaders mid-write; use sidecar which uploads blocks atomically enough
- Monitor compactor logs for download errors — a flaky storage backend corrupts downloads repeatedly
When it happens
Trigger: metadata.ReadFromDir(bdir) returns an error during repairBucketBlock after block.Download succeeds: meta.json missing from the downloaded block directory, meta.json unparseable JSON, meta.json failing validation (invalid ULID, minTime>maxTime, missing thanos.version field for Thanos-written blocks, mismatched block id between directory name and meta), or the download produced an empty/partial directory that still passed block.Download's checks.
Common situations: Object storage corruption or truncated uploads of meta.json; blocks uploaded by very old Prometheus/Thanos versions lacking required meta fields; partial block downloads from flaky object storage backends (S3 throttling, network interruption) where the index downloaded fine but meta.json did not; a bucket containing a directory that is not a real TSDB block (e.g. a marker file or partial upload from a crashed uploader).
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/8d86223916a0bb48.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/compact/compact.go:1136
tmpdir, err := os.MkdirTemp("", fmt.Sprintf("repair-issue-347-id-%s-", ie.id))
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(tmpdir); err != nil {
level.Warn(logger).Log("msg", "failed to remote tmpdir", "err", err, "tmpdir", tmpdir)
}
}()
bdir := filepath.Join(tmpdir, ie.id.String())
if err := block.Download(ctx, logger, bkt, ie.id, bdir); err != nil {
return retry(errors.Wrapf(err, "download block %s", ie.id))
}
meta, err := metadata.ReadFromDir(bdir)
if err != nil {
return errors.Wrapf(err, "read meta from %s", bdir)
}
resid, err := block.Repair(ctx, logger, tmpdir, ie.id, metadata.CompactorRepairSource, block.IgnoreIssue347OutsideChunk)
if err != nil {
return errors.Wrapf(err, "repair failed for block %s", ie.id)
}
// Verify repaired id before uploading it.
if err := block.VerifyIndex(ctx, logger, filepath.Join(tmpdir, resid.String(), block.IndexFilename), meta.MinTime, meta.MaxTime); err != nil {
return errors.Wrapf(err, "repaired block is invalid %s", resid)
}
level.Info(logger).Log("msg", "uploading repaired block", "newID", resid)
if err = block.Upload(ctx, logger, bkt, filepath.Join(tmpdir, resid.String()), metadata.NoneFunc); err != nil {
return retry(errors.Wrapf(err, "upload of %s failed", resid))
}
level.Info(logger).Log("msg", "deleting broken block", "id", ie.id)View on GitHub (pinned to 35b8b99117)