{"record":{"id":"66aa468cb46be7e6","repo":"gastownhall/beads","slug":"cannot-remove-the-primary-worktree","errorCode":null,"errorMessage":"cannot remove the primary worktree","messagePattern":"cannot remove the primary worktree","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/worktreeremove/policy.go","lineNumber":176,"sourceCode":"func (plan Plan) Cleanup() (Cleanup, bool) {\n\tif plan.managedIgnoreEntry == \"\" {\n\t\treturn Cleanup{}, false\n\t}\n\treturn Cleanup{Entry: plan.managedIgnoreEntry}, true\n}\n\nfunc (plan Plan) valid() bool {\n\treturn plan.approved && (plan.mode == Normal || plan.mode == Force) && plan.targetPath != \"\"\n}\n\n// Prepare validates the initial observations and returns an approved plan.\nfunc Prepare(request Request, facts PrepareFacts) (Plan, error) {\n\tif request.Mode != Normal && request.Mode != Force {\n\t\treturn Plan{}, fmt.Errorf(\"worktree removal mode is absent or invalid\")\n\t}\n\tswitch facts.Target {\n\tcase PrimaryWorktree:\n\t\treturn Plan{}, fmt.Errorf(\"cannot remove the primary worktree\")\n\tcase CurrentWorktree:\n\t\treturn Plan{}, fmt.Errorf(\"cannot remove the worktree containing the running command\")\n\tcase RegisteredTarget:\n\tdefault:\n\t\treturn Plan{}, fmt.Errorf(\"registered worktree target is absent or invalid\")\n\t}\n\tif facts.Registration != Present || facts.RegisteredPath == \"\" ||\n\t\tfacts.TargetDir != Present || facts.GitAdminDir != Present ||\n\t\tfacts.GitMarker != Present || facts.Head != Present {\n\t\treturn Plan{}, fmt.Errorf(\"registered worktree target is absent or invalid\")\n\t}\n\tif facts.CommonDir != Matched {\n\t\treturn Plan{}, fmt.Errorf(\"target common git directory does not match repository\")\n\t}\n\tif facts.Status != Clean && facts.Status != Dirty {\n\t\treturn Plan{}, fmt.Errorf(\"worktree cleanliness observation is absent or invalid\")\n\t}\n\tif facts.ManagedIgnore != IgnoreAbsent && facts.ManagedIgnore != IgnoreManaged {","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/worktreeremove/policy.go#L158-L194","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nplan, err := worktreeremove.Prepare(worktreeremove.Request{\n    Target: worktreeremove.PrimaryWorktree,\n    Mode:   worktreeremove.Normal,\n}, facts)\n\n// after\nif target == worktreeremove.PrimaryWorktree {\n    return fmt.Errorf(\"refusing: cannot remove the primary worktree\")\n}\nplan, err := worktreeremove.Prepare(worktreeremove.Request{\n    Target: worktreeremove.RegisteredTarget,\n    Mode:   worktreeremove.Normal,\n}, facts)","handlingStrategy":"validation","validationCode":"if facts.Target == worktreeremove.PrimaryWorktree {\n    return fmt.Errorf(\"%s is the primary worktree; refusing to remove\", registeredPath)\n}","typeGuard":"func removable(facts worktreeremove.PrepareFacts) bool {\n    return facts.Target == worktreeremove.RegisteredTarget\n}","tryCatchPattern":"plan, err := worktreeremove.Prepare(req, facts)\nif err != nil && strings.Contains(err.Error(), \"primary worktree\") {\n    return fmt.Errorf(\"cannot remove the primary worktree; choose a linked worktree\")\n}","preventionTips":["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."],"tags":["validation","worktree","git","policy"],"backgroundTag":"operation-not-permitted","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}