{"record":{"id":"d0f2c48d843359a7","repo":"gastownhall/beads","slug":"atomicfile-rename-w","errorCode":null,"errorMessage":"atomicfile: rename: %w","messagePattern":"atomicfile: rename: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/atomicfile/atomicfile.go","lineNumber":95,"sourceCode":"\t\t_ = w.f.Close()\n\t\t_ = os.Remove(w.f.Name())\n\t\treturn fmt.Errorf(\"atomicfile: chmod: %w\", err)\n\t}\n\n\tif err := w.f.Sync(); err != nil {\n\t\t_ = w.f.Close()\n\t\t_ = os.Remove(w.f.Name())\n\t\treturn fmt.Errorf(\"atomicfile: sync: %w\", err)\n\t}\n\n\tif err := w.f.Close(); err != nil {\n\t\t_ = os.Remove(w.f.Name())\n\t\treturn fmt.Errorf(\"atomicfile: close: %w\", err)\n\t}\n\n\tif err := os.Rename(w.f.Name(), w.target); err != nil {\n\t\t_ = os.Remove(w.f.Name())\n\t\treturn fmt.Errorf(\"atomicfile: rename: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Abort discards the temp file without renaming. The target is untouched.\n// Safe to call multiple times or after Close.\nfunc (w *Writer) Abort() error {\n\tif w.done {\n\t\treturn nil\n\t}\n\tw.done = true\n\t_ = w.f.Close()\n\treturn os.Remove(w.f.Name())\n}\n","sourceCodeStart":77,"sourceCodeEnd":111,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/atomicfile/atomicfile.go#L77-L111","documentation":"The final step of an atomic write is os.Rename(tempFile, target). If the rename fails, the temp file is removed and this wrapped error is returned; the original target file (if any) is never partially modified.","triggerScenarios":"Rename fails when the target directory became unwritable or was removed mid-write, when target and temp end up on different filesystems, when the target path is a directory, or on Windows when the target is open/locked by another process.","commonSituations":"Another process deleting .beads while bd writes, exporting onto a different mount than expected, or Windows antivirus/indexer holding the destination file open.","solutions":["Ensure no other process locks or removes the target during the write (close editors/sync tools, use file locking)","Verify target directory exists and is writable at rename time","Keep the target on the same filesystem as the temp file (rename is same-FS only)"],"exampleFix":"// before\natomicfile.Create(\"/mnt/usb/out.jsonl\", 0644) // temp on /tmp FS? mismatch\n// after\natomicfile.Create(\"/mnt/usb/.beads/out.jsonl\", 0644) // temp created in same dir","handlingStrategy":"retry","validationCode":"dir := filepath.Dir(path)\nif info, err := os.Stat(dir); err != nil || !info.IsDir() {\n    return fmt.Errorf(\"target dir missing: %s\", dir)\n}","typeGuard":null,"tryCatchPattern":"err := writeAtomic(path, data) // wraps atomicfile\nfor i := 0; i < 3 && err != nil; i++ {\n    if strings.Contains(err.Error(), \"atomicfile: rename\") {\n        time.Sleep(100 * time.Millisecond) // transient lock on Windows/sync tools\n        err = writeAtomic(path, data)\n        continue\n    }\n    break\n}","preventionTips":["Stop sync/backup tools from holding the target open during writes (esp. Windows)","Never delete or replace the target directory mid-write","Keep temp and target on the same filesystem (default behavior)"],"tags":["filesystem","atomic-write","rename"],"backgroundTag":"file-rename-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}