gastownhall/beads · error
scanning open wisps for references: %w
Error message
scanning open wisps for references: %w
What it means
This wraps a failure from CommentUseCase().GetCommentsForWisps while reading comments for open wisps (the ephemeral plane) during the sweep reference scan. Wisps' comments live in a separate wisp_comments table; a failure there means the scan cannot prove candidates unreferenced, so the sweep aborts rather than under-scan and delete a bead cited only by a wisp comment.
Source
Thrown at internal/storage/uow/sweeper.go:167
// BOTH PLANES, and this is not an optimization detail. The not-done set
// comes from SearchIssues, which merges the durable and wisp planes, so it
// contains wisps — and their comments live in wisp_comments, which
// GetCommentsForIssues does not read. Scanning only the durable table left
// a closed bead cited solely by a comment on an open WISP unprotected, so
// `bd prune` deleted it on this route and kept it on the other. The
// contract says an implementation that cannot read the full set must fail
// the sweep rather than under-scan it.
//
// The full id list goes to both reads rather than being partitioned by a
// plane flag: an id lives in exactly one plane, so at most one side answers
// for it, and a mis-partition here would silently under-scan again.
comments, err := uw.CommentUseCase().GetCommentsForIssues(ctx, notDoneIDs)
if err != nil {
return nil, fmt.Errorf("scanning open beads for references: %w", err)
}
wispComments, err := uw.CommentUseCase().GetCommentsForWisps(ctx, notDoneIDs)
if err != nil {
return nil, fmt.Errorf("scanning open wisps for references: %w", err)
}
for id, cs := range wispComments {
comments[id] = append(comments[id], cs...)
}
referenced := make(map[string]bool)
for _, issue := range notDone {
if issue == nil {
continue
}
matcher.FindAll(issue.Description, referenced)
matcher.FindAll(issue.Notes, referenced)
for _, c := range comments[issue.ID] {
matcher.FindAll(c.Text, referenced)
}
}
return referenced, nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause and fix the underlying wisp-comments query failure
- Retry the sweep once the database is reachable
- Raise query timeouts / batch size limits for very large wisp sets
- Run database repair/consistency tooling if corruption is reported
Defensive patterns
Strategy: retry
Validate before calling
// Ensure the wisp comments table is readable before sweeping
rows, err := db.QueryContext(ctx, "SELECT 1 FROM wisp_comments LIMIT 1")
if err != nil {
return fmt.Errorf("wisp_comments not readable, skip sweep: %w", err)
}
rows.Close() Try / catch
result, err := sweeper.Sweep(ctx, req)
if err != nil && strings.Contains(err.Error(), "scanning open wisps for references") {
// wisp-plane comment read failed; restore DB health and retry
return retrySweepWithBackoff(ctx, req)
} Prevention
- Compact/expire stale wisps regularly to keep the wisp set small
- Keep the Dolt connection alive for the full sweep duration
- Apply schema migrations after beads upgrades before sweeping
- Monitor for corruption and repair early
When it happens
Trigger: bd prune/sweep when the batched wisp_comments query for the not-done ID list fails — SQL error on the wisp plane, connection loss, or timeout on a large not-done set.
Common situations: Large numbers of open wisps making the batch query slow; Dolt server restart mid-sweep; schema drift in wisp_comments between beads versions.
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
- wisp plane membership: %w
- GetForIssueIDs (wisps): %w
- GetWispDependencyRecords: %w
- applyGraph: read existing wisp deps for %s: %w
- delete: drop wisp deps: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/867a99c8f83903ef.
Report an issue: GitHub.