gastownhall/beads · error
cannot safely prepare .gitignore cleanup: %w
Error message
cannot safely prepare .gitignore cleanup: %w
What it means
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.
Source
Thrown at cmd/bd/worktree_cmd.go:1314
GitMarker: worktreeremove.Present,
CommonDir: worktreeremove.Matched,
Head: worktreeremove.Present,
Status: status,
ManagedIgnore: worktreeremove.IgnoreAbsent,
}
if !sameWorktreePath(target.commonDir, mainCommonDir) {
plan.prepareFacts.CommonDir = worktreeremove.Unmatched
plan.prepareErr = fmt.Errorf(
"target common git directory %q does not match repository %q",
target.commonDir,
mainCommonDir,
)
return plan, nil
}
if relative, inside := relativeWorktreePath(plan.mainWorktree, target.path); inside {
plan.gitignoreCleanup, err = prepareGitignoreCleanup(plan.mainWorktree, relative)
if err != nil {
return nil, fmt.Errorf("cannot safely prepare .gitignore cleanup: %w", err)
}
if plan.gitignoreCleanup != nil {
plan.prepareFacts.ManagedIgnore = worktreeremove.IgnoreManaged
plan.prepareFacts.ManagedIgnoreEntry = plan.gitignoreCleanup.entry
}
}
if options.force.value {
plan.prepareFacts.Comparator = worktreeremove.ComparatorNotRequired
plan.prepareFacts.Containment = worktreeremove.ContainmentNotRequired
return plan, nil
}
if target.status != "" {
return plan, nil
}
var comparator pinnedWorktreeComparator
if options.mergedInto.set {View on GitHub (pinned to 71377f2769)
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
Example fix
// before $ ls -l .gitignore # -rw------- root $ bd worktree remove nested-wt // error: cannot safely prepare .gitignore cleanup: open .gitignore: permission denied // after $ sudo chown $(whoami) .gitignore && chmod u+w .gitignore $ bd worktree remove nested-wt
Defensive patterns
Strategy: validation
Validate before calling
[ -w .gitignore ] || { echo '.gitignore not writable'; exit 1; }
realpath .gitignore >/dev/null 2>&1 || { echo '.gitignore path unsafe'; exit 1; } Type guard
func canPrepareGitignore(mainWorktree string) bool {
info, err := os.Stat(filepath.Join(mainWorktree, ".gitignore"))
return err == nil && info.Mode().Perm()&0200 != 0
} Try / catch
if err != nil && strings.Contains(err.Error(), "cannot safely prepare .gitignore cleanup") {
return fmt.Errorf("fix .gitignore permissions or remove the ignore entry manually, then retry")
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: .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.
Related errors
- target git directory is not a real directory: %s
- failed to pin target git marker identity: %w
- target directory identity changed
- target git directory identity changed
- target git marker identity changed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b1f97746f764bfe2.
Report an issue: GitHub.