gastownhall/beads · error

worktree removal failure is absent or invalid

Error message

worktree removal failure is absent or invalid

What it means

ClassifyFailure exists to explain a removal error, so removeErr must be non-nil. If the caller invokes it after a removal that reported success (or with a nil error), there is nothing to classify and the function returns this error rather than fabricating an UnchangedFailure or PartialFailure result.

Source

Thrown at internal/worktreeremove/policy.go:335

const (
	UnchangedFailure FailureKind = iota
	PartialFailure
)

// Failure is the pure classification returned after a mutation error.
type Failure struct {
	Kind      FailureKind
	RemoveErr error
}

// ClassifyFailure distinguishes a safely unchanged target from partial or
// indeterminate state. Presentation retains diagnostics at the command edge.
func ClassifyFailure(plan Plan, facts FailureFacts, removeErr error) (Failure, error) {
	if !plan.valid() {
		return Failure{}, fmt.Errorf("worktree removal approval is absent or invalid")
	}
	if removeErr == nil {
		return Failure{}, fmt.Errorf("worktree removal failure is absent or invalid")
	}
	if facts.RevalidationResult == RevalidationPassed && facts.Registration == Present && facts.TargetPath == Present && revalidationValid(plan, facts.Revalidation) {
		return Failure{Kind: UnchangedFailure, RemoveErr: removeErr}, nil
	}
	return Failure{Kind: PartialFailure, RemoveErr: removeErr}, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Only call ClassifyFailure when the removal function returned a non-nil error.
  2. On removal success, take the success path instead of invoking classification.
  3. If removal semantics changed, check err from Remove before deciding to classify.

Example fix

// before
classification, err := ClassifyFailure(plan, ffacts, removeErr)

// after
if removeErr != nil {
	classification, err = ClassifyFailure(plan, ffacts, removeErr)
} else {
	// removal succeeded — success path
}
Defensive patterns

Strategy: validation

Validate before calling

if removeErr == nil {
	// success path — do not call ClassifyFailure
	return nil
}
classification, err := ClassifyFailure(plan, ffacts, removeErr)

Prevention

When it happens

Trigger: Calling ClassifyFailure with removeErr == nil, typically when the caller's control flow reaches failure classification unconditionally instead of only when RemoveWorktree returned an error.

Common situations: Copy-pasted error handling where the nil-error success branch is missing; wrapper code that logs/classifies regardless of removal outcome; refactoring that inverted an if condition around the remove call.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b1fc9d71f41bff34. Report an issue: GitHub.