gastownhall/beads · error
hydrate neighbors (wisps): %w
Error message
hydrate neighbors (wisps): %w
What it means
Wraps a failure from issueRepo.GetByIDs against the wisp table (IssueTableOpts{UseWispsTable:true}) during neighbor hydration in collectConnectedIssues. A missing wisp table is tolerated (dberrors.IsTableNotExist), so this error only fires for genuine storage failures on the wisp plane — e.g. a real query error while reading wisp_neighbor rows.
Source
Thrown at internal/storage/domain/issue_delete.go:388
if len(neighbors) == 0 {
return out, isWisp, nil
}
ids := make([]string, 0, len(neighbors))
for id := range neighbors {
ids = append(ids, id)
}
fromIssues, err := u.issueRepo.GetByIDs(ctx, ids, IssueTableOpts{})
if err != nil {
return nil, nil, fmt.Errorf("hydrate neighbors (issues): %w", err)
}
for _, iss := range fromIssues {
out[iss.ID] = iss
}
fromWisps, err := u.issueRepo.GetByIDs(ctx, ids, IssueTableOpts{UseWispsTable: true})
if err != nil && !dberrors.IsTableNotExist(err) {
return nil, nil, fmt.Errorf("hydrate neighbors (wisps): %w", err)
}
for _, iss := range fromWisps {
out[iss.ID] = iss
isWisp[iss.ID] = true
}
return out, isWisp, nil
}
func (u *issueUseCaseImpl) rewriteTextReferences(
ctx context.Context, deletedIDs []string,
connected map[string]*types.Issue, isWisp map[string]bool, actor string,
) (int, error) {
touched := make(map[string]bool)
for _, id := range deletedIDs {
pattern := `(^|[^A-Za-z0-9_-])(` + regexp.QuoteMeta(id) + `)($|[^A-Za-z0-9_-])`
re := regexp.MustCompile(pattern)
replacement := `$1[deleted:` + id + `]$3`
for connID, conn := range connected {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause; if it is a table-missing error, verify dberrors.IsTableNotExist handling covers your driver's error shape.
- Check database connectivity/locks and retry the delete.
- Rerun with a fresh context to rule out cancellation from an upstream request.
- If the wisp table is corrupted, repair or recreate the wisp plane (bd doctor) before deleting.
- Confirm your storage driver version supports the wisps table schema in use.
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm store health before delete
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("store unreachable: %w", err) } Type guard
func isHydrateWispsErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "hydrate neighbors (wisps)")
} Try / catch
err := usecase.DeleteMany(ctx, ids)
if err != nil && strings.Contains(err.Error(), "hydrate neighbors (wisps)") {
cause := errors.Unwrap(err)
if !dberrors.IsTableNotExist(cause) {
return fmt.Errorf("wisp hydration failed: %w", cause) // retry or escalate
}
} Prevention
- Keep the storage driver version in sync with the wisps-table schema
- Retry transient errors once with backoff before failing the whole delete
- Monitor Dolt server health for stores using the wisp plane
- Run bd doctor periodically to catch wisp-table corruption early
When it happens
Trigger: deleteMany/previewDelete with dependency-connected neighbors where the wisps table exists but the bulk GetByIDs on it fails: driver error, connection loss, context cancellation, or malformed query results.
Common situations: Mixed durable/wisp stores where the wisp table is present but corrupted; transient Dolt server errors during delete; canceled long deletes; driver version mismatch causing query incompatibility on the wisp table.
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
- delete: drop wisp deps: %w
- delete: drop wisp rows: %w
- applyGraph: read existing wisp deps for %s: %w
- delete: drop deps: %w
- delete: drop sync-plane edges into deleted wisps: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e4845fd4b02b4152.
Report an issue: GitHub.