gastownhall/beads · error
failed to batch delete wisps: %w
Error message
failed to batch delete wisps: %w
What it means
This error wraps a failure of the core DELETE FROM wisps WHERE id IN (...) statement inside the batch delete transaction. Everything before it (affected-set computation, existing-ID resolution, edge journaling) succeeded, but the actual row deletion failed, so the transaction rolls back with no wisps removed.
Source
Thrown at internal/storage/dolt/wisps.go:461
// 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()
// The batched wisp delete surface carries no actor, so the rows record none.
for _, id := range deletedIDs {
if err := issueops.RecordDeleteInTx(ctx, tx, id, ""); err != nil {
return 0, err
}
}
if err := issueops.DeleteWispsFromDependenciesInTx(ctx, tx, ids); err != nil {
return 0, err
}
if err := deleteWispAuxRowsInTx(ctx, tx, ids); err != nil {
return 0, fmt.Errorf("delete wisp aux rows: %w", err)
}
View on GitHub (pinned to 71377f2769)
Solutions
- Retry the delete; the wrapper batches at 200 IDs so transient failures are safe to re-attempt (nothing committed on failure)
- If calling internals directly, chunk ID lists to ≤200 to stay within Dolt's write timeout
- Check for concurrent writers/locks on the wisps table and serialize GC with other mutating jobs
- Verify the database is writable (not a read-only replica) and the connection is alive; check the wrapped driver error for specifics
Example fix
// before
store.deleteWispBatchTx(ctx, hugeIDSlice) // >200 ids: oversized IN clause, write timeout
// after
for i := 0; i < len(ids); i += 200 {
end := i + 200
if end > len(ids) { end = len(ids) }
if _, err := store.deleteWispBatchTx(ctx, ids[i:end]); err != nil { return err }
} Defensive patterns
Strategy: retry
Validate before calling
// Go: chunk large ID sets before calling delete internals
if len(ids) > 200 {
return errors.New("split IDs into batches of <=200 before deleting")
}
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("dolt unreachable: %w", err) } Try / catch
n, err := store.DeleteWisps(ctx, ids)
if err != nil {
if strings.Contains(err.Error(), "failed to batch delete wisps") {
// transaction rolled back atomically; safe to retry
time.Sleep(2 * time.Second)
n, err = store.DeleteWisps(ctx, ids)
}
return err
} Prevention
- Rely on the library's internal 200-id batching; never build oversized IN clauses yourself
- Serialize GC with other writers to avoid row-lock contention on wisps
- Verify the database is writable (not a read-only replica) before maintenance
- Retry on transient failures — the per-batch transaction guarantees atomicity
When it happens
Trigger: The parameterized DELETE errors: Dolt connection dropped mid-transaction, write timeout exceeded, table locked by a concurrent writer, or malformed/oversized IN clause (more IDs than the driver/server can handle).
Common situations: Deleting thousands of IDs in one statement against a remote Dolt server with a 10s write timeout; another process holding a row lock on wisps; server restarted between BeginTx and ExecContext; running against a read-only replica.
Related errors
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to set dolt_force_transaction_commit: %w
- failed to begin regular tx: %w
- failed to begin ignored tx: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5bb601e013c72774.
Report an issue: GitHub.