{"record":{"id":"d24813af1844da39","repo":"thanos-io/thanos","slug":"not-a-block-dir","errorCode":null,"errorMessage":"not a block dir","messagePattern":"not a block dir","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/block/block.go","lineNumber":123,"sourceCode":"}\n\n// upload uploads block from given block dir that ends with block id.\n// It makes sure cleanup is done on error to avoid partial block uploads.\n// TODO(bplotka): Ensure bucket operations have reasonable backoff retries.\n// NOTE: Upload updates `meta.Thanos.File` section.\nfunc upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir string, hf metadata.HashFunc, checkExternalLabels bool, options ...objstore.UploadOption) error {\n\tdf, err := os.Stat(bdir)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !df.IsDir() {\n\t\treturn errors.Errorf(\"%s is not a directory\", bdir)\n\t}\n\n\t// Verify dir.\n\tid, err := ulid.Parse(df.Name())\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"not a block dir\")\n\t}\n\n\tmeta, err := metadata.ReadFromDir(bdir)\n\tif err != nil {\n\t\t// No meta or broken meta file.\n\t\treturn errors.Wrap(err, \"read meta\")\n\t}\n\n\tif checkExternalLabels {\n\t\tif len(meta.Thanos.Labels) == 0 {\n\t\t\treturn errors.New(\"empty external labels are not allowed for Thanos block.\")\n\t\t}\n\t}\n\n\tmetaEncoded := strings.Builder{}\n\tmeta.Thanos.Files, err = GatherFileStats(bdir, hf, logger)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"gather meta file stats\")","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/block.go#L105-L141","documentation":"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.","triggerScenarios":"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).","commonSituations":"Uploading a raw Prometheus TSDB data dir; temp/scratch directories; paths with trailing slashes or typos; custom tooling creating non-ULID directory names.","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"],"exampleFix":"// before\nerr := block.Upload(ctx, logger, bkt, \"/data/tmp-block\", hf, true)\n// after\nif _, err := ulid.Parse(filepath.Base(\"/data/tmp-block\")); err != nil {\n    return fmt.Errorf(\"refusing upload: %w\", err)\n}\nerr = block.Upload(ctx, logger, bkt, \"/data/tmp-block\", hf, true)","handlingStrategy":"validation","validationCode":"if _, err := ulid.Parse(filepath.Base(bdir)); err != nil {\n    return fmt.Errorf(\"%s is not a ULID block dir: %w\", bdir, err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["validation","ulid","upload"],"backgroundTag":"invalid-identifier-format","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}