thanos-io/thanos · error
not a block dir
Error message
not a block dir
What it means
upload() verifies the directory name parses as a ULID (the block ID). If base name of bdir is not a valid ULID, the wrapped 'not a block dir' error is returned, since Thanos blocks must live in ULID-named directories.
Solutions
- Ensure the directory name is a valid 26-character ULID; regenerate/rename if needed
- Only upload directories produced by Thanos/Prometheus block creation (block.UploadPromBlock or Prometheus shipper)
- Validate with ulid.Parse(bdir base name) before uploading
Example fix
// before
err := block.Upload(ctx, logger, bkt, "/data/tmp-block", hf, true)
// after
if _, err := ulid.Parse(filepath.Base("/data/tmp-block")); err != nil {
return fmt.Errorf("refusing upload: %w", err)
}
err = block.Upload(ctx, logger, bkt, "/data/tmp-block", hf, true) Defensive patterns
Strategy: validation
Validate before calling
if _, err := ulid.Parse(filepath.Base(bdir)); err != nil {
return fmt.Errorf("%s is not a ULID block dir: %w", bdir, err)
} Prevention
- Only upload directories produced by Prometheus/Thanos block writers
- Skip known non-block dirs (tmp, junk) when walking storage
- Keep trailing slashes out of the path so base name is the ULID
When it happens
Trigger: Calling block.Upload / UploadPromBlock with a directory whose base name is not a valid ULID (e.g. 'blocks/tmp', 'chunks', an empty name, or a Prometheus block not yet renamed).
Common situations: Uploading a raw Prometheus TSDB data dir; temp/scratch directories; paths with trailing slashes or typos; custom tooling creating non-ULID directory names.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- ULID is not valid
- is not a directory
- unsupported format for label
- --auto-gomemlimit.ratio must be greater than 0 and less…
- unexpected downsampling resolution
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/d24813af1844da39.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/block/block.go:123
}
// upload uploads block from given block dir that ends with block id.
// It makes sure cleanup is done on error to avoid partial block uploads.
// TODO(bplotka): Ensure bucket operations have reasonable backoff retries.
// NOTE: Upload updates `meta.Thanos.File` section.
func upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir string, hf metadata.HashFunc, checkExternalLabels bool, options ...objstore.UploadOption) error {
df, err := os.Stat(bdir)
if err != nil {
return err
}
if !df.IsDir() {
return errors.Errorf("%s is not a directory", bdir)
}
// Verify dir.
id, err := ulid.Parse(df.Name())
if err != nil {
return errors.Wrap(err, "not a block dir")
}
meta, err := metadata.ReadFromDir(bdir)
if err != nil {
// No meta or broken meta file.
return errors.Wrap(err, "read meta")
}
if checkExternalLabels {
if len(meta.Thanos.Labels) == 0 {
return errors.New("empty external labels are not allowed for Thanos block.")
}
}
metaEncoded := strings.Builder{}
meta.Thanos.Files, err = GatherFileStats(bdir, hf, logger)
if err != nil {
return errors.Wrap(err, "gather meta file stats")View on GitHub (pinned to 35b8b99117)