thanos-io/thanos · error

read new meta

Error message

read new meta

What it means

InjectThanos wraps any failure from ReadFromDir, which parses the meta.json inside a TSDB block directory, before attaching Thanos metadata. It means the block's meta.json could not be read or decoded, so the Thanos section cannot be injected. The library throws this because writing a block without valid metadata would leave an unusable block.

Solutions

  1. Verify bdir is the actual block directory and contains a readable meta.json before calling InjectThanos.
  2. Check that the block write (e.g. tsdb block creation) completed successfully before injecting Thanos meta.
  3. Inspect the wrapped error (permissions, JSON decode) and fix the underlying cause.
  4. Re-create the block if meta.json is corrupt or missing.

Example fix

// before
meta, err := InjectThanos(logger, bucketRoot, thanosMeta, nil) // wrong dir
// after
meta, err := InjectThanos(logger, filepath.Join(bucketRoot, blockID.String()), thanosMeta, nil)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(filepath.Join(bdir, "meta.json")); err != nil {
    return fmt.Errorf("block dir %s has no meta.json: %w", bdir, err)
}

Type guard

func hasMetaJSON(bdir string) bool {
    fi, err := os.Stat(filepath.Join(bdir, "meta.json"))
    return err == nil && !fi.IsDir()
}

Try / catch

meta, err := InjectThanos(logger, bdir, thanosMeta, nil)
if err != nil {
    if strings.Contains(err.Error(), "read new meta") {
        logger.Log("msg", "meta.json missing/corrupt; re-creating block", "dir", bdir, "err", err)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling InjectThanos on a directory (bdir) that has no meta.json, a corrupt/truncated meta.json, malformed JSON, or a directory that does not exist after block creation.

Common situations: Block creation failed or was interrupted so meta.json was never written; passing the wrong path (e.g. the bucket root instead of the block dir); meta.json deleted or corrupted by concurrent tooling; filesystem errors (permissions, disk full).

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/532dcaabc02edc2d. Report an issue: GitHub.

Appendix: source

Thrown at pkg/block/metadata/meta.go:181

type File struct {
	RelPath string `json:"rel_path"`
	// SizeBytes is optional (e.g meta.json does not show size).
	SizeBytes int64 `json:"size_bytes,omitempty"`

	// Hash is an optional hash of this file. Used for potentially avoiding an extra download.
	Hash *ObjectHash `json:"hash,omitempty"`
}

type ThanosDownsample struct {
	Resolution int64 `json:"resolution"`
}

// InjectThanos sets Thanos meta to the block meta JSON and saves it to the disk.
// NOTE: It should be used after writing any block by any Thanos component, otherwise we will miss crucial metadata.
func InjectThanos(logger log.Logger, bdir string, meta Thanos, downsampledMeta *tsdb.BlockMeta) (*Meta, error) {
	newMeta, err := ReadFromDir(bdir)
	if err != nil {
		return nil, errors.Wrap(err, "read new meta")
	}
	newMeta.Thanos = meta

	// While downsampling we need to copy original compaction.
	if downsampledMeta != nil {
		newMeta.Compaction = downsampledMeta.Compaction
	}

	if err := newMeta.WriteToDir(logger, bdir); err != nil {
		return nil, errors.Wrap(err, "write new meta")
	}

	return newMeta, nil
}

// GroupKey returns a unique identifier for the compaction group the block belongs to.
// It considers the downsampling resolution and the block's labels.
func (m *Thanos) GroupKey() string {

View on GitHub (pinned to 35b8b99117)