{"record":{"id":"46b3433c51adc150","repo":"gastownhall/beads","slug":"worktree-removal-interrupted-after-target-resoluti","errorCode":null,"errorMessage":"worktree removal interrupted after target resolution: %w","messagePattern":"worktree removal interrupted after target resolution: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/bd/worktree_cmd.go","lineNumber":1258,"sourceCode":"\t\treturn nil, err\n\t}\n\tplan := &worktreeRemovalPlan{\n\t\tforce: options.force.value,\n\t\tprepareFacts: worktreeremove.PrepareFacts{\n\t\t\tRegistration: worktreeremove.Present,\n\t\t},\n\t}\n\tif targetEntry.isMain {\n\t\tplan.prepareFacts.Target = worktreeremove.PrimaryWorktree\n\t\treturn plan, nil\n\t}\n\tif sameWorktreePath(targetEntry.path, currentRoot) {\n\t\tplan.prepareFacts.Target = worktreeremove.CurrentWorktree\n\t\treturn plan, nil\n\t}\n\tif afterTargetResolution != nil {\n\t\tif err := afterTargetResolution(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"worktree removal interrupted after target resolution: %w\", err)\n\t\t}\n\t}\n\n\tmainCommonDirOutput, err := gitRunner.output(\n\t\tctx,\n\t\tmainWorktree.path,\n\t\t\"rev-parse\",\n\t\t\"--path-format=absolute\",\n\t\t\"--git-common-dir\",\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to resolve repository common git directory: %w\", err)\n\t}\n\tmainCommonDir := filepath.Clean(strings.TrimSpace(string(mainCommonDirOutput)))\n\n\ttarget, err := inspectWorktreeTarget(ctx, gitRunner, targetEntry)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":1240,"sourceCodeEnd":1276,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/worktree_cmd.go#L1240-L1276","documentation":"This error reports that a caller-injected interruption hook (`afterTargetResolution`) returned an error while bd was building the worktree removal plan, after the target worktree had been resolved but before any mutation. bd wraps the hook's error so it is clear the abort happened at the 'after target resolution' checkpoint of the removal pipeline. It is a deliberate abort mechanism (used by tests/preview flows), not an internal fault.","triggerScenarios":"Any worktree removal that passes an `afterTargetResolution` callback (testing hooks, preview/confirm flows) where the callback returns a non-nil error — e.g. a user answering 'no' at a confirmation prompt or a test injecting an abort.","commonSituations":"Interactive confirmation cancelled by the user; automated tests simulating a crash between target resolution and common-dir inspection; external tooling aborting the plan mid-way.","solutions":["Inspect the wrapped cause (%w) to see why the hook aborted; that cause is the real error","Re-run the removal and accept the confirmation/hook when prompted","If a test or script injects the abort, fix the hook to return nil when removal should proceed"],"exampleFix":"// before\nafterTargetResolution: func() error { return errors.New(\"user cancelled\") }\n// after: proceed with removal\nafterTargetResolution: nil // or return nil from the hook","handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"plan, err := buildWorktreeRemovalPlan(ctx, git, name, afterHook)\nvar we *fmt.wrapError\nif err != nil && errors.As(err, &we) {\n\treturn fmt.Errorf(\"removal aborted at afterTargetResolution: %v\", we.Unwrap())\n}","preventionTips":["Ensure afterTargetResolution hooks return nil when removal should proceed","Treat this error as an expected abort path, not a bug","Log the unwrapped cause for user-facing messaging","Don't do mutating work inside the hook — keep it a pure decision point"],"tags":["git","worktree","cancellation"],"backgroundTag":"operation-aborted-by-hook","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}