{"record":{"id":"6b5daea41b8774d1","repo":"thanos-io/thanos","slug":"replace-index-file","errorCode":null,"errorMessage":"replace index file","messagePattern":"replace index file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/block/writer.go","lineNumber":140,"sourceCode":"\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 {\n\t\td.closers = nil\n\t\treturn tsdb.BlockStats{}, err\n\t}\n\td.closers = nil\n\n\t// Block files successfully written, make them visible by moving files from tmp dir.\n\tif err := fileutil.Replace(filepath.Join(d.bTmp, IndexFilename), filepath.Join(d.bDir, IndexFilename)); err != nil {\n\t\treturn tsdb.BlockStats{}, errors.Wrap(err, \"replace index file\")\n\t}\n\tif err := fileutil.Replace(filepath.Join(d.bTmp, ChunksDirname), filepath.Join(d.bDir, ChunksDirname)); err != nil {\n\t\treturn tsdb.BlockStats{}, errors.Wrap(err, \"replace chunks dir\")\n\t}\n\treturn d.stats, nil\n}\n\ntype statsGatheringSeriesWriter struct {\n\tiw tsdb.IndexWriter\n\tcw tsdb.ChunkWriter\n\n\tstats   tsdb.BlockStats\n\tsymbols int64\n}\n\nfunc (s *statsGatheringSeriesWriter) AddSymbol(sym string) error {\n\tif err := s.iw.AddSymbol(sym); err != nil {\n\t\treturn err","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/writer.go#L122-L158","documentation":"Flush fails when fileutil.Replace cannot move the finished index file from the tmp dir to the final block directory, making the block visible. This is the finalization step of block publication; a failure here leaves the block unpublished with files stranded in the tmp dir.","triggerScenarios":"fileutil.Replace(<bTmp>/index, <bDir>/index) failing due to cross-device rename (EXDEV), destination permission denied, destination being a non-empty directory, or source file missing (earlier step failed silently).","commonSituations":"bTmp and bDir accidentally on different filesystems/mount points; bDir read-only or owned by another user; an existing corrupt index in bDir conflicting with replacement; concurrent flushes racing on the same block.","solutions":["Ensure bTmp and bDir are on the same filesystem so rename/replace works.","Check write permissions on the final block directory (d.bDir).","Remove conflicting stale index files in the destination block dir.","Prevent concurrent Flush calls on the same DiskWriter/block dir and retry."],"exampleFix":"// before\nd, err := NewDiskWriter(ctx, logger, \"/mnt/nfs/blocks/01BK...\") // tmp on tmpfs\n// after: keep bdir and its tmp dir on the same volume\nd, err := NewDiskWriter(ctx, logger, \"/data/blocks/01BK...\")","handlingStrategy":"validation","validationCode":"tmpDev, err := deviceID(filepath.Join(bdir, \"tmp-for-creation\"))\nif err != nil { return err }\ndestDev, err := deviceID(bdir)\nif err != nil { return err }\nif tmpDev != destDev {\n    return fmt.Errorf(\"tmp dir and block dir are on different filesystems (%d vs %d)\", tmpDev, destDev)\n}","typeGuard":null,"tryCatchPattern":"if _, err := d.Flush(ctx); err != nil {\n    if strings.Contains(err.Error(), \"replace index file\") {\n        return fmt.Errorf(\"block finalization failed (fs/permission conflict): %w\", err)\n    }\n    return err\n}","preventionTips":["Keep the whole block directory tree on a single filesystem/mount.","Verify write permissions on the destination block dir before compaction.","Serialize Flush calls per block dir to avoid rename races."],"tags":["go","block-writer","rename","filesystem"],"backgroundTag":"file-write-failed","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"}