{"record":{"id":"049cdd2775495652","repo":"gastownhall/beads","slug":"failed-to-create-temp-file-w","errorCode":null,"errorMessage":"failed to create temp file: %w","messagePattern":"failed to create temp file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/backup_export.go","lineNumber":100,"sourceCode":"// atomicWriteFile writes data to a same-directory temp file, fsyncs the\n// temp file's own contents, then renames it into place. This avoids a\n// truncated/partial file at path if the process crashes mid-write.\n//\n// Two caveats this does NOT cover, narrowing the \"crash-safe\" claim rather\n// than the implementation (existing callers' behavior is unchanged here):\n//   - Only the temp file's contents are fsynced, not the parent directory\n//     entry; a crash between the rename and a subsequent directory fsync\n//     can still lose the rename itself on some filesystems.\n//   - os.Rename's atomic-replace guarantee is a POSIX/Unix property; it is\n//     not guaranteed on Windows. It also does not follow a symlink at\n//     path — it replaces whatever is there, symlink or not — so a caller\n//     that must preserve a symlink's target should resolve path with\n//     filepath.EvalSymlinks first (see cmd/bd/proxied_server.go).\nfunc atomicWriteFile(path string, data []byte) error {\n\tdir := filepath.Dir(path)\n\ttmp, err := os.CreateTemp(dir, \".backup-tmp-*\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temp file: %w\", err)\n\t}\n\ttmpPath := tmp.Name()\n\n\tif _, err := tmp.Write(data); err != nil {\n\t\t_ = tmp.Close()\n\t\t_ = os.Remove(tmpPath)\n\t\treturn fmt.Errorf(\"failed to write temp file: %w\", err)\n\t}\n\tif err := tmp.Sync(); err != nil {\n\t\t_ = tmp.Close()\n\t\t_ = os.Remove(tmpPath)\n\t\treturn fmt.Errorf(\"failed to sync temp file: %w\", err)\n\t}\n\tif err := tmp.Close(); err != nil {\n\t\t_ = os.Remove(tmpPath)\n\t\treturn fmt.Errorf(\"failed to close temp file: %w\", err)\n\t}\n\tif err := os.Rename(tmpPath, path); err != nil {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/backup_export.go#L82-L118","documentation":"atomicWriteFile calls os.CreateTemp in the target file's directory to stage content before an atomic rename. This error wraps CreateTemp failure — the directory doesn't exist, isn't writable, or the OS refused temp-file creation.","triggerScenarios":"os.CreateTemp(filepath.Dir(path), \".backup-tmp-*\") fails: parent directory missing (e.g. .beads/ deleted), read-only filesystem, disk full of inodes, or permission denied on the directory.","commonSituations":".beads directory removed while bd ran; running inside a read-only container mount; full disk/inode exhaustion; wrong user without write access to .beads; TMP restrictions on hardened systems.","solutions":["Ensure the target directory exists: mkdir -p .beads (atomicWriteFile does not create parent dirs).","Check write permission on the directory: ls -ld .beads and chmod/chown appropriately.","Check disk space and inodes: df -h and df -i.","If on a read-only mount, remount read/write or point BD_DIR at a writable location."],"exampleFix":"// shell\nmkdir -p .beads && chmod u+w .beads && bd sync","handlingStrategy":"validation","validationCode":"dir := \".beads\"\ninfo, err := os.Stat(dir)\nif err != nil || !info.IsDir() {\n    os.MkdirAll(dir, 0o755)\n}\n// probe writability with a real temp create (same mechanism bd uses)\nif f, err := os.CreateTemp(dir, \".probe-*\"); err == nil { f.Close(); os.Remove(f.Name()) }","typeGuard":"func dirIsWritable(dir string) bool {\n    f, err := os.CreateTemp(dir, \".probe-*\")\n    if err != nil { return false }\n    f.Close(); os.Remove(f.Name())\n    return true\n}","tryCatchPattern":"if err := saveBackupState(dir, state); err != nil {\n    if strings.Contains(err.Error(), \"create temp file\") {\n        if mkErr := os.MkdirAll(dir, 0o755); mkErr == nil {\n            err = saveBackupState(dir, state) // one retry after ensuring dir\n        }\n    }\n    if err != nil { return err }\n}","preventionTips":["Never delete or replace the .beads directory while bd commands run","Check df -h and df -i before large operations","Keep the workspace on a writable mount, not a read-only container layer","Use consistent user ownership across CI and local runs"],"tags":["go","filesystem","permissions","atomic-write"],"backgroundTag":"permission-denied","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}