{"record":{"id":"33775c4e39002165","repo":"thanos-io/thanos","slug":"read-dir-v","errorCode":null,"errorMessage":"read dir %v","messagePattern":"read dir (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/block/block.go","lineNumber":330,"sourceCode":"func GetSegmentFiles(blockDir string) []string {\n\tfiles, err := os.ReadDir(filepath.Join(blockDir, ChunksDirname))\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\t// ReadDir returns files in sorted order already.\n\tvar result []string\n\tfor _, f := range files {\n\t\tresult = append(result, f.Name())\n\t}\n\treturn result\n}\n\n// GatherFileStats returns metadata.File entry for files inside TSDB block (index, chunks, meta.json).\nfunc GatherFileStats(blockDir string, hf metadata.HashFunc, logger log.Logger) (res []metadata.File, _ error) {\n\tfiles, err := os.ReadDir(filepath.Join(blockDir, ChunksDirname))\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"read dir %v\", filepath.Join(blockDir, ChunksDirname))\n\t}\n\tfor _, f := range files {\n\t\tfi, err := f.Info()\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrapf(err, \"getting file info %v\", filepath.Join(ChunksDirname, f.Name()))\n\t\t}\n\n\t\tmf := metadata.File{\n\t\t\tRelPath:   filepath.Join(ChunksDirname, f.Name()),\n\t\t\tSizeBytes: fi.Size(),\n\t\t}\n\t\tif hf != metadata.NoneFunc && !f.IsDir() {\n\t\t\th, err := metadata.CalculateHash(filepath.Join(blockDir, ChunksDirname, f.Name()), hf, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Wrapf(err, \"calculate hash %v\", filepath.Join(ChunksDirname, f.Name()))\n\t\t\t}\n\t\t\tmf.Hash = &h\n\t\t}","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/block.go#L312-L348","documentation":"GatherFileStats enumerates the chunks/ directory of a local TSDB block to build per-file metadata (size, hash). This error wraps os.ReadDir on <blockDir>/chunks failing — the directory does not exist or is unreadable. It surfaces when uploading a block whose on-disk structure is broken.","triggerScenarios":"upload() calls GatherFileStats on a block directory that lacks a chunks/ subdirectory, or where ReadDir fails due to permissions or an I/O error (e.g., disk failure, NFS issue).","commonSituations":"Prometheus data directory partially deleted or corrupted; wrong --data-dir path; block dir being concurrently deleted while being uploaded; volume mount issues in containers.","solutions":["Verify the block directory actually contains a chunks/ subdirectory (ls <blockDir>).","Check filesystem permissions on the block dir and that the process user can read it.","Confirm --data-dir points at a healthy Prometheus/TSDB data directory.","Exclude/remove the corrupted block from the upload queue (or repair it from a replica)."],"exampleFix":"// before\nfiles, err := os.ReadDir(filepath.Join(blockDir, ChunksDirname))\nif err != nil {\n\treturn nil, errors.Wrapf(err, \"read dir %v\", filepath.Join(blockDir, ChunksDirname))\n}\n// after\nif _, err := os.Stat(filepath.Join(blockDir, ChunksDirname)); os.IsNotExist(err) {\n\treturn nil, errors.Errorf(\"block dir %s has no chunks directory; block is incomplete\", blockDir)\n}\nfiles, err := os.ReadDir(filepath.Join(blockDir, ChunksDirname))","handlingStrategy":"validation","validationCode":"chunksDir := filepath.Join(blockDir, \"chunks\")\nif fi, err := os.Stat(chunksDir); err != nil || !fi.IsDir() {\n\treturn fmt.Errorf(\"block %s unusable: chunks dir missing\", blockDir)\n}\nif _, err := os.Stat(filepath.Join(blockDir, \"meta.json\")); err != nil {\n\treturn fmt.Errorf(\"block %s unusable: meta.json missing\", blockDir)\n}\nif _, err := os.Stat(filepath.Join(blockDir, \"index\")); err != nil {\n\treturn fmt.Errorf(\"block %s unusable: index missing\", blockDir)\n}","typeGuard":"func isCompleteBlockDir(dir string) bool {\n\tfor _, p := range []string{\"meta.json\", \"index\", \"chunks\"} {\n\t\tif _, err := os.Stat(filepath.Join(dir, p)); err != nil { return false }\n\t}\n\treturn true\n}","tryCatchPattern":"files, err := block.GatherFileStats(blockDir, hashFunc, logger)\nif err != nil {\n\tif os.IsNotExist(errors.Unwrap(err)) {\n\t\treturn fmt.Errorf(\"block %s incomplete, skipping upload\", blockDir)\n\t}\n\treturn err\n}","preventionTips":["Only upload fully finalized block directories (with meta.json present).","Never delete Prometheus data while the thanos sidecar/shipper is running.","Verify the data-dir mount is healthy and not read-only/incomplete.","Filter candidate block dirs with a completeness check before upload."],"tags":["filesystem","thanos","tsdb"],"backgroundTag":"directory-not-found","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"}