gastownhall/beads · error
cannot remove the primary worktree
Error message
cannot remove the primary worktree
What it means
Prepare refuses any removal whose Target is PrimaryWorktree: the main worktree of a repository can never be removed via this policy, because deleting it would destroy the repository's primary checkout. Only registered linked worktrees (Target == RegisteredTarget) are eligible. This is an unconditional policy refusal, independent of the supplied facts.
Source
Thrown at internal/worktreeremove/policy.go:176
func (plan Plan) Cleanup() (Cleanup, bool) {
if plan.managedIgnoreEntry == "" {
return Cleanup{}, false
}
return Cleanup{Entry: plan.managedIgnoreEntry}, true
}
func (plan Plan) valid() bool {
return plan.approved && (plan.mode == Normal || plan.mode == Force) && plan.targetPath != ""
}
// Prepare validates the initial observations and returns an approved plan.
func Prepare(request Request, facts PrepareFacts) (Plan, error) {
if request.Mode != Normal && request.Mode != Force {
return Plan{}, fmt.Errorf("worktree removal mode is absent or invalid")
}
switch facts.Target {
case PrimaryWorktree:
return Plan{}, fmt.Errorf("cannot remove the primary worktree")
case CurrentWorktree:
return Plan{}, fmt.Errorf("cannot remove the worktree containing the running command")
case RegisteredTarget:
default:
return Plan{}, fmt.Errorf("registered worktree target is absent or invalid")
}
if facts.Registration != Present || facts.RegisteredPath == "" ||
facts.TargetDir != Present || facts.GitAdminDir != Present ||
facts.GitMarker != Present || facts.Head != Present {
return Plan{}, fmt.Errorf("registered worktree target is absent or invalid")
}
if facts.CommonDir != Matched {
return Plan{}, fmt.Errorf("target common git directory does not match repository")
}
if facts.Status != Clean && facts.Status != Dirty {
return Plan{}, fmt.Errorf("worktree cleanliness observation is absent or invalid")
}
if facts.ManagedIgnore != IgnoreAbsent && facts.ManagedIgnore != IgnoreManaged {View on GitHub (pinned to 71377f2769)
Solutions
- Skip the primary worktree: filter it out of any worktree list before building removal requests.
- Point the operation at a linked worktree (Target: RegisteredTarget) instead.
- If the intent is to remove the whole repository, use a different workflow (delete the repo) — this API will never allow it.
- In automation, detect PrimaryWorktree early and return a friendly message instead of calling Prepare.
Example fix
// before
plan, err := worktreeremove.Prepare(worktreeremove.Request{
Target: worktreeremove.PrimaryWorktree,
Mode: worktreeremove.Normal,
}, facts)
// after
if target == worktreeremove.PrimaryWorktree {
return fmt.Errorf("refusing: cannot remove the primary worktree")
}
plan, err := worktreeremove.Prepare(worktreeremove.Request{
Target: worktreeremove.RegisteredTarget,
Mode: worktreeremove.Normal,
}, facts) Defensive patterns
Strategy: validation
Validate before calling
if facts.Target == worktreeremove.PrimaryWorktree {
return fmt.Errorf("%s is the primary worktree; refusing to remove", registeredPath)
} Type guard
func removable(facts worktreeremove.PrepareFacts) bool {
return facts.Target == worktreeremove.RegisteredTarget
} Try / catch
plan, err := worktreeremove.Prepare(req, facts)
if err != nil && strings.Contains(err.Error(), "primary worktree") {
return fmt.Errorf("cannot remove the primary worktree; choose a linked worktree")
} Prevention
- Filter out the primary worktree when iterating `git worktree list` entries.
- Resolve the target path against the registered worktree list to classify Target before Prepare.
- Provide clear UX: hide or disable remove for the primary checkout.
When it happens
Trigger: Calling Prepare with Request{Target: PrimaryWorktree} in any Mode; a CLI resolving the current directory or configured path to the primary worktree and passing it as the removal target.
Common situations: User runs the remove command while pointed at the repo's root checkout; automation that iterates over all `git worktree list` entries including the first (primary) one; misconfigured script defaulting to the repo root.
Related errors
- worktree removal mode is absent or invalid
- cannot remove the worktree containing the running command
- registered worktree target is absent or invalid
- target git marker is not a regular file: %s
- git returned invalid commit object ID %q
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/66aa468cb46be7e6.
Report an issue: GitHub.