{"record":{"id":"b1f97746f764bfe2","repo":"gastownhall/beads","slug":"cannot-safely-prepare-gitignore-cleanup-w","errorCode":null,"errorMessage":"cannot safely prepare .gitignore cleanup: %w","messagePattern":"cannot safely prepare \\.gitignore cleanup: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/worktree_cmd.go","lineNumber":1314,"sourceCode":"\t\tGitMarker:      worktreeremove.Present,\n\t\tCommonDir:      worktreeremove.Matched,\n\t\tHead:           worktreeremove.Present,\n\t\tStatus:         status,\n\t\tManagedIgnore:  worktreeremove.IgnoreAbsent,\n\t}\n\tif !sameWorktreePath(target.commonDir, mainCommonDir) {\n\t\tplan.prepareFacts.CommonDir = worktreeremove.Unmatched\n\t\tplan.prepareErr = fmt.Errorf(\n\t\t\t\"target common git directory %q does not match repository %q\",\n\t\t\ttarget.commonDir,\n\t\t\tmainCommonDir,\n\t\t)\n\t\treturn plan, nil\n\t}\n\tif relative, inside := relativeWorktreePath(plan.mainWorktree, target.path); inside {\n\t\tplan.gitignoreCleanup, err = prepareGitignoreCleanup(plan.mainWorktree, relative)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot safely prepare .gitignore cleanup: %w\", err)\n\t\t}\n\t\tif plan.gitignoreCleanup != nil {\n\t\t\tplan.prepareFacts.ManagedIgnore = worktreeremove.IgnoreManaged\n\t\t\tplan.prepareFacts.ManagedIgnoreEntry = plan.gitignoreCleanup.entry\n\t\t}\n\t}\n\n\tif options.force.value {\n\t\tplan.prepareFacts.Comparator = worktreeremove.ComparatorNotRequired\n\t\tplan.prepareFacts.Containment = worktreeremove.ContainmentNotRequired\n\t\treturn plan, nil\n\t}\n\tif target.status != \"\" {\n\t\treturn plan, nil\n\t}\n\n\tvar comparator pinnedWorktreeComparator\n\tif options.mergedInto.set {","sourceCodeStart":1296,"sourceCodeEnd":1332,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/worktree_cmd.go#L1296-L1332","documentation":"When the target worktree lives inside the primary worktree's directory tree, bd plans to clean the managed .gitignore entry that ignored it. This error wraps a failure of `prepareGitignoreCleanup` — bd could not safely compute or stage the .gitignore edit (unreadable file, unsafe relative path, write problems), and aborts the removal rather than leaving a stale ignore entry or editing the wrong file.","triggerScenarios":"`bd worktree remove` of a nested worktree (target path inside the main worktree) where prepareGitignoreCleanup fails: the main .gitignore is unreadable/unwritable, the relative path escapes or is ambiguous (symlinks, `..`), or concurrent modification makes the entry unsafe to match.","commonSituations":".gitignore with restrictive permissions or owned by another user; symlinked worktree paths; worktree created at a path like `../repo` that resolves oddly; .gitignore with unusual encoding/huge size.","solutions":["Check permissions on the primary worktree's .gitignore and make it writable by the current user","Remove the worktree's ignore entry manually from .gitignore, then retry the removal","Inspect the wrapped cause (%w): fix the specific path/symlink problem it reports (e.g. use the real, non-symlink path when creating the worktree)","As a fallback, remove the worktree with `git worktree remove` and clean the .gitignore entry yourself"],"exampleFix":"// before\n$ ls -l .gitignore  # -rw------- root\n$ bd worktree remove nested-wt\n// error: cannot safely prepare .gitignore cleanup: open .gitignore: permission denied\n// after\n$ sudo chown $(whoami) .gitignore && chmod u+w .gitignore\n$ bd worktree remove nested-wt","handlingStrategy":"validation","validationCode":"[ -w .gitignore ] || { echo '.gitignore not writable'; exit 1; }\nrealpath .gitignore >/dev/null 2>&1 || { echo '.gitignore path unsafe'; exit 1; }","typeGuard":"func canPrepareGitignore(mainWorktree string) bool {\n\tinfo, err := os.Stat(filepath.Join(mainWorktree, \".gitignore\"))\n\treturn err == nil && info.Mode().Perm()&0200 != 0\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"cannot safely prepare .gitignore cleanup\") {\n\treturn fmt.Errorf(\"fix .gitignore permissions or remove the ignore entry manually, then retry\")\n}","preventionTips":["Keep .gitignore writable by the user running bd","Avoid symlinked worktree paths for nested worktrees","Create worktrees outside the primary tree when possible to skip ignore management","Check ownership/permissions after provisioning environments as root"],"tags":["git","worktree","gitignore","filesystem"],"backgroundTag":"gitignore-cleanup-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}