gastownhall/beads · error
resolve existing wisps for batch delete: %w
Error message
resolve existing wisps for batch delete: %w
What it means
This error wraps failures from issueops.ExistingIssueIDsInTableInTx, which resolves which of the requested wisp IDs actually exist in the wisps table before the DELETE runs. The transaction must know the real deleted set so delete-journal records are only written for wisps it actually removes (RowsAffected gives a count, not a set). If this lookup fails, the batch aborts and rolls back.
Source
Thrown at internal/storage/dolt/wisps.go:446
}
defer func() { _ = tx.Rollback() }()
clearJournalScope := s.scopeEventsJournalTransaction(tx)
defer clearJournalScope()
affectedIssues, affectedWisps, aerr := issueops.AffectedByDeletionInTx(ctx, tx, nil, ids)
if aerr != nil {
return 0, fmt.Errorf("affected by batched wisp delete: %w", aerr)
}
// Resolve WHICH wisps this batch actually removes before the DELETE runs:
// afterwards they are gone, and RowsAffected reports a count, not a set.
// GC hands this path ids it scanned earlier, so an already-collected wisp is
// a routine case, and a phantom delete record would tell a consumer to drop
// a bead this transaction never touched.
deletedIDs, err := issueops.ExistingIssueIDsInTableInTx(ctx, tx, "wisps", ids)
if err != nil {
return 0, fmt.Errorf("resolve existing wisps for batch delete: %w", err)
}
// Edges are journaled before the rows go, while their source snapshots can
// still be read.
if err := issueops.RecordDependencyRemovalsForIssuesInTx(ctx, tx, deletedIDs); err != nil {
return 0, fmt.Errorf("journal dependency removals for batched wisp delete: %w", err)
}
inClause, args := doltBuildSQLInClause(ids)
//nolint:gosec // G201: inClause contains only ? markers
result, err := tx.ExecContext(ctx,
fmt.Sprintf("DELETE FROM wisps WHERE id IN (%s)", inClause),
args...)
if err != nil {
return 0, fmt.Errorf("failed to batch delete wisps: %w", err)
}
rowsAffected, _ := result.RowsAffected()
View on GitHub (pinned to 71377f2769)
Solutions
- Confirm the wisps table exists and is intact (run the tool's doctor/check or dolt schema inspect); re-run migrations if needed
- Retry after restoring Dolt connectivity; already-collected wisps being absent is routine and handled, only the query itself failing raises this
- Address the wrapped driver error (timeout, lock, cancelled ctx) reported in the error chain
- Ensure the caller's context is not cancelled prematurely (increase timeout, check signal handling)
Defensive patterns
Strategy: retry
Validate before calling
// Go: pre-check reachability; existence of individual IDs is handled internally
if err := ctx.Err(); err != nil { return err }
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("dolt unreachable: %w", err) } Try / catch
_, err := store.DeleteWisps(ctx, ids)
if err != nil && strings.Contains(err.Error(), "resolve existing wisps") {
// transient lookup failure: retry once after backoff
time.Sleep(time.Second)
_, err = store.DeleteWisps(ctx, ids)
}
return err Prevention
- Retry batch deletes — they are transactional and safe to re-attempt
- Ensure the wisps table schema is current (run migrations after upgrades)
- Don't pre-filter IDs yourself; the path tolerates already-collected wisps
- Avoid running deletes while the Dolt server is restarting or unreachable
When it happens
Trigger: DeleteWisps/GC delete path where the SELECT used by ExistingIssueIDsInTableInTx against the wisps table errors: lost Dolt connection, cancelled context, or a missing/corrupt wisps table.
Common situations: Database file locked or server unavailable during GC; running bd against a repo whose schema predates the wisps table; transient network failure between agent and a remote Dolt server.
Related errors
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- reading gate %s: %w
- iter issues: query: %w
- failed to set dolt_force_transaction_commit: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b675c537d906ecc2.
Report an issue: GitHub.