{"record":{"id":"4be40bfe4de59538","repo":"thanos-io/thanos","slug":"open-temporary-block-dir","errorCode":null,"errorMessage":"open temporary block dir","messagePattern":"open temporary block dir","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/block/writer.go","lineNumber":114,"sourceCode":"\t\treturn nil, errors.Wrap(err, \"open index writer\")\n\t}\n\td.closers = append(d.closers, indexw)\n\td.statsGatheringSeriesWriter = statsGatheringSeriesWriter{iw: indexw, cw: chunkw}\n\treturn d, nil\n}\n\nfunc (d *DiskWriter) Flush() (_ tsdb.BlockStats, err error) {\n\tdefer func() {\n\t\tif err != nil {\n\t\t\terr = tsdb_errors.NewMulti(err, tsdb_errors.CloseAll(d.closers)).Err()\n\t\t\tif err := os.RemoveAll(d.bTmp); err != nil {\n\t\t\t\tlevel.Error(d.logger).Log(\"msg\", \"removed tmp folder failed after block(s) write\", \"err\", err.Error())\n\t\t\t}\n\t\t}\n\t}()\n\tdf, err := fileutil.OpenDir(d.bTmp)\n\tif err != nil {\n\t\treturn tsdb.BlockStats{}, errors.Wrap(err, \"open temporary block dir\")\n\t}\n\tdefer func() {\n\t\tif df != nil {\n\t\t\terr = tsdb_errors.NewMulti(err, df.Close()).Err()\n\t\t}\n\t}()\n\n\tif err := df.Sync(); err != nil {\n\t\treturn tsdb.BlockStats{}, errors.Wrap(err, \"sync temporary dir file\")\n\t}\n\n\t// Close temp dir before rename block dir (for windows platform).\n\tif err = df.Close(); err != nil {\n\t\treturn tsdb.BlockStats{}, errors.Wrap(err, \"close temporary dir\")\n\t}\n\tdf = nil\n\n\tif err := tsdb_errors.CloseAll(d.closers); err != nil {","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/writer.go#L96-L132","documentation":"Flush fails when fileutil.OpenDir cannot open the temporary block directory for reading. Flush finalizes the block by syncing, closing writers, and renaming the tmp dir; if the tmp dir cannot even be opened, finalization cannot proceed and the block is not published.","triggerScenarios":"fileutil.OpenDir(d.bTmp) failing because the temp block dir was deleted (e.g. by concurrent cleanup), was never created, the path changed, or an OS-level open error occurred (permissions, fd exhaustion).","commonSituations":"Two compactions/uploads racing on the same block dir and one removing the tmp folder; tmp dir cleaned by a janitor mid-flush; too many open files; wrong bdir passed so bTmp never existed.","solutions":["Ensure no other process concurrently removes the <block>/tmp-for-creation directory.","Confirm Flush is called on the same DiskWriter instance/dir used for writes.","Check filesystem permissions and open-file limits (ulimit -n).","If the block write failed earlier, discard and re-create the block instead of flushing."],"exampleFix":"// before\n// janitor goroutine: os.RemoveAll(tmpDir) while Flush is running\n// after\n// guard: only remove tmpDir if writer flush failed and is not in progress","handlingStrategy":"retry","validationCode":"tmpDir := filepath.Join(bdir, \"tmp-for-creation\")\nif fi, err := os.Stat(tmpDir); err != nil || !fi.IsDir() {\n    return fmt.Errorf(\"tmp dir %s missing before flush\", tmpDir)\n}","typeGuard":null,"tryCatchPattern":"if _, err := d.Flush(ctx); err != nil {\n    if strings.Contains(err.Error(), \"open temporary block dir\") {\n        // transient removal race: rebuild block\n        return fmt.Errorf(\"tmp dir vanished during flush; re-run compaction: %w\", err)\n    }\n    return err\n}","preventionTips":["Never run concurrent writers or janitors on the same block directory.","Raise open-file limits (ulimit -n) on compaction hosts.","Only remove tmp-for-creation dirs when no Flush is in progress."],"tags":["go","block-writer","directory-not-found","filesystem"],"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"}