{"record":{"id":"52955454380fd264","repo":"gastownhall/beads","slug":"d-artifact-s-could-not-be-removed","errorCode":null,"errorMessage":"%d artifact(s) could not be removed","messagePattern":"(.+?) artifact\\(s\\) could not be removed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/fix/artifacts.go","lineNumber":54,"sourceCode":"\t\tremoved += r\n\t\tskipped += s\n\t\terrCount += e\n\n\t\treturn filepath.SkipDir\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to walk directory tree: %w\", err)\n\t}\n\n\t// Report summary\n\tfmt.Printf(\"  Artifact cleanup: %d removed, %d skipped, %d errors\\n\", removed, skipped, errCount)\n\n\tif skipped > 0 {\n\t\tfmt.Println(\"  Skipped items may need manual review (e.g., issues.jsonl in dolt dirs, beads.db files)\")\n\t}\n\n\tif errCount > 0 {\n\t\treturn fmt.Errorf(\"%d artifact(s) could not be removed\", errCount)\n\t}\n\n\treturn nil\n}\n\n// cleanBeadsDirArtifacts cleans artifacts from a single .beads directory.\n// Returns counts of removed, skipped, and errored items.\nfunc cleanBeadsDirArtifacts(beadsDir string) (removed, skipped, errCount int) {\n\thasDolt := hasDoltDir(beadsDir)\n\tisRedirectExpected := isRedirectExpectedLocation(beadsDir)\n\n\t// 1. Clean JSONL artifacts in dolt-native directories\n\tif hasDolt {\n\t\tr, s, e := cleanJSONLArtifacts(beadsDir)\n\t\tremoved += r\n\t\tskipped += s\n\t\terrCount += e\n\t}","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/fix/artifacts.go#L36-L72","documentation":"ClassicArtifacts walks a repo tree for .beads directories and deletes legacy artifacts (stale JSONL exports, SQLite WAL/SHM files, backup DBs, cruft files in redirect-only .beads dirs). It continues past individual removal failures, counting them, and at the end returns this aggregated error reporting how many artifacts could not be removed. It is a batch-cleanup result error, not a single-failure error — the per-item causes are only visible in the 'errors' count of the summary line, and skipped (not deleted) items are reported separately and do not trigger it.","triggerScenarios":"Calling fix.ClassicArtifacts(path) when one or more artifact files it tries to delete cannot be removed — e.g. os.Remove fails due to file permissions, read-only filesystem, a file locked by a running process (a live bd process holding beads.db-wal open), or a cruft-file removal failing inside cleanCruftBeadsDirFiles in an expected-redirect .beads directory.","commonSituations":"Running `bd doctor --fix` on a repo while a bd daemon or another bd process still has SQLite WAL/SHM files open; cleaning a .beads directory owned by another user or checked out with restrictive permissions; running on a read-only mount or CI workspace with artifact files made immutable; Windows file locking on beads.db-wal.","solutions":["Stop all running bd processes/daemons that could hold .beads files open, then rerun `bd doctor --fix` (or fix.ClassicArtifacts).","Check permissions and ownership of the reported .beads directories; chown/chmod so the current user can delete the files, or run with sufficient privileges.","Inspect each .beads directory named in the summary for files that cannot be deleted (immutable flag on Linux: chattr -i; locked handles on Windows) and remove them manually.","If artifacts live on a read-only or immutable CI checkout, run the fix in a writable workspace instead.","Rerun the cleanup and confirm the summary reports 0 errors."],"exampleFix":"// before\nerr := fix.ClassicArtifacts(\".\") // fails while bd daemon holds beads.db-wal\n\n// after\n// 1. stop the daemon (or `bd daemon stop`), then:\nif err := fix.ClassicArtifacts(\".\"); err != nil {\n\tfmt.Printf(\"some artifacts need manual cleanup: %v\\n\", err)\n\tos.Exit(1)\n}","handlingStrategy":"validation","validationCode":"// Pre-flight: ensure no live bd process holds .beads files and dirs are writable\nlsof +D .beads 2>/dev/null && echo \"bd files in use — stop bd first\"\ntest -w .beads || echo \".beads not writable by current user\"","typeGuard":"func canClean(beadsDir string) bool {\n\tentries, err := os.ReadDir(beadsDir)\n\tif err != nil {\n\t\treturn false\n\t}\n\tfor _, e := range entries {\n\t\tif err := unix.Access(filepath.Join(beadsDir, e.Name()), unix.W_OK); err != nil {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","tryCatchPattern":"if err := fix.ClassicArtifacts(path); err != nil {\n\t// summary line above already listed per-item failures\n\tfmt.Fprintf(os.Stderr, \"artifact cleanup incomplete (%v) — remove remaining files manually\", err)\n}","preventionTips":["Stop bd daemons/processes before running doctor artifact cleanup","Run `bd doctor --fix` as the same user that owns the .beads directory","Avoid read-only or immutable CI checkouts for fix operations","On Windows, ensure no editor/AV holds beads.db-wal open","Rerun cleanup after fixing causes and check the 'N errors' summary reaches 0"],"tags":["go","filesystem","cleanup","permissions","doctor-fix"],"backgroundTag":"file-remove-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}