gastownhall/beads · error

reading custom statuses for wisp age GC: %w

Error message

reading custom statuses for wisp age GC: %w

What it means

During wisp age-based garbage collection, protectedWispStatuses builds the set of statuses that must not be collected, including custom statuses categorized as WIP or Frozen. If reading the custom status definitions from the repository fails, the GC cannot know what is protected and aborts with this wrapped error rather than risk deleting wisps it should preserve.

Source

Thrown at cmd/bd/wisp.go:688

	protected := make(map[types.Status]bool)
	for _, s := range []types.Status{
		types.StatusOpen,
		types.StatusInProgress,
		types.StatusBlocked,
		types.StatusClosed,
		types.StatusDeferred,
		types.StatusPinned,
		types.StatusHooked,
	} {
		switch types.BuiltInStatusCategory(s) {
		case types.CategoryWIP, types.CategoryFrozen:
			protected[s] = true
		}
	}

	customStatuses, err := r.GetCustomStatusesDetailed(ctx)
	if err != nil {
		return nil, fmt.Errorf("reading custom statuses for wisp age GC: %w", err)
	}
	for _, cs := range customStatuses {
		switch cs.Category {
		case types.CategoryWIP, types.CategoryFrozen:
			protected[types.Status(cs.Name)] = true
		}
	}
	return protected, nil
}

// isProtectedWisp reports whether a wisp is live work that age-based GC must
// never reclaim. A wisp is protected if it is explicitly pinned, if it is
// blocked on an open dependency (blockedSet, derived from is_blocked), or if
// its status falls in a protected category. Reclaiming any of these
// mid-execution destroys active molecules (GH#4394).
//
// Named isProtectedWisp rather than isActiveWisp to avoid confusion with
// (*DoltStore).isActiveWisp in internal/storage/dolt, which is in this same

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check database connectivity and retry the GC command
  2. Inspect/repair custom status configuration (`bd statuses` or equivalent)
  3. Investigate the wrapped inner error (%w) for the root cause
Defensive patterns

Strategy: retry

Validate before calling

if err := pingStore(ctx, r); err != nil {
    return fmt.Errorf("store unreachable; defer wisp GC: %w", err)
}

Try / catch

if err := runWispGC(ctx); err != nil {
    var wrapped string = err.Error()
    if strings.Contains(wrapped, "reading custom statuses for wisp age GC") {
        // retry with backoff or skip GC this cycle; never GC without the protected set
    }
}

Prevention

When it happens

Trigger: findAbandonedWisps calls r.GetCustomStatusesDetailed(ctx) and the underlying store/driver returns an error (database unavailable, corrupted status config, driver failure).

Common situations: Database locked or unreachable during GC runs in CI; Dolt/storage driver failures; corrupted custom-status configuration in .beads metadata.

Related errors


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