gastownhall/beads · error
determining wisp status for %s: %w
Error message
determining wisp status for %s: %w
What it means
uowMolWriter.isWisp caches whether an issue ID is an ephemeral 'wisp' by calling GetWisp. If GetWisp returns an error that is neither success nor sql.ErrNoRows (i.e. a real storage failure, not 'not a wisp'), it wraps it as 'determining wisp status for <id>'. This guards against misclassifying storage errors as 'not a wisp'.
Source
Thrown at cmd/bd/mol_port.go:389
}
func (w *uowMolWriter) isWisp(ctx context.Context, id string) (bool, error) {
if w.wispIDs[id] {
return true, nil
}
if w.notWispIDs[id] {
return false, nil
}
_, err := w.uw.IssueUseCase().GetWisp(ctx, id)
if err == nil {
w.wispIDs[id] = true
return true, nil
}
if errors.Is(err, sql.ErrNoRows) {
w.notWispIDs[id] = true
return false, nil
}
return false, fmt.Errorf("determining wisp status for %s: %w", id, err)
}
func (w *uowMolWriter) CreateIssue(ctx context.Context, issue *types.Issue, actor string) error {
params := domain.CreateIssueParams{Issue: issue, ExplicitID: issue.ID, Labels: issue.Labels}
var err error
if issue.Ephemeral || issue.NoHistory {
_, err = w.uw.IssueUseCase().CreateWisp(ctx, params, actor)
if err == nil {
w.wispIDs[issue.ID] = true
}
} else {
_, err = w.uw.IssueUseCase().CreateIssue(ctx, params, actor)
if err == nil {
w.notWispIDs[issue.ID] = true
}
}
return err
}View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause to identify the real storage error
- If a driver upgrade changed the not-found sentinel, map it to sql.ErrNoRows at the driver boundary (per the storage boundary policy)
- Check database health and retry transient failures (bd doctor)
- If caused by context cancellation, increase timeout or re-run the operation
Example fix
// before: driver returns custom ErrNotFound, isWisp treats it as a hard error
_, err := w.uw.IssueUseCase().GetWisp(ctx, id)
// after: normalize at the driver boundary so errors.Is(err, sql.ErrNoRows) works
if errors.Is(err, driver.ErrNotFound) {
return nil, sql.ErrNoRows
} Defensive patterns
Strategy: try-catch
Validate before calling
// probe wisp lookup before performing writes
if _, err := uw.IssueUseCase().GetWisp(ctx, id); err != nil && !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("storage unhealthy for %s: %w", id, err)
} Type guard
func isWispLookupFailure(err error) bool {
return err != nil && !errors.Is(err, sql.ErrNoRows) && !errors.Is(err, context.Canceled)
} Try / catch
if err := writer.UpdateIssue(ctx, issue, actor); err != nil {
if strings.Contains(err.Error(), "determining wisp status") {
// underlying GetWisp failed; check storage, retry
}
return err
} Prevention
- Keep the storage driver's not-found errors normalized to sql.ErrNoRows at the driver boundary
- Avoid long-running operations that hold a context near expiry while touching many IDs
- Run bd doctor to verify DB health before bulk molecule mutations
- Watch for driver upgrades that change sentinel error types
When it happens
Trigger: Calling AddDependency, UpdateIssue, CloseIssue, or ClaimStepIfOpen on a uowMolWriter when the underlying GetWisp storage lookup fails with a non-not-found error: DB corruption, driver failure, context cancellation, or unexpected error types that don't map to sql.ErrNoRows.
Common situations: Storage driver returning a custom not-found error type that no longer matches sql.ErrNoRows (behavior change after driver/upgrade); locked or inaccessible Dolt database; context deadline exceeded during a long molecule operation.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- get molecule children: %w
- failed to close wisp root %s: %w
- failed to clear ephemeral flag on root %s: %w
- remove dep: classify source: %w
- ClaimReadyWisp: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bb674edba4b7a3f2.
Report an issue: GitHub.