gastownhall/beads · error
delete issues: %w
Error message
delete issues: %w
What it means
DeleteResolvedSetInTx fails with this when the batched `DELETE FROM issues WHERE id IN (...)` statement errors. Regular (non-wisp) issues are removed in batches of deleteBatchSize inside one transaction; any SQL-level failure aborts the whole delete.
Source
Thrown at internal/storage/issueops/delete.go:321
if err := deleteIssueRowInTx(ctx, tx, id, true); err != nil {
return nil, fmt.Errorf("delete wisp %s: %w", id, err)
}
}
totalRegularsDeleted := 0
for i := 0; i < len(set.RegularIDs); i += deleteBatchSize {
end := i + deleteBatchSize
if end > len(set.RegularIDs) {
end = len(set.RegularIDs)
}
batch := set.RegularIDs[i:end]
batchInClause, batchArgs := buildSQLInClause(batch)
deleteResult, err := tx.ExecContext(ctx,
fmt.Sprintf(`DELETE FROM issues WHERE id IN (%s)`, batchInClause),
batchArgs...)
if err != nil {
return nil, fmt.Errorf("delete issues: %w", err)
}
rowsAffected, _ := deleteResult.RowsAffected()
totalRegularsDeleted += int(rowsAffected)
// Deleted issues hold no leases.
if _, err := tx.ExecContext(ctx,
fmt.Sprintf(`DELETE FROM leases WHERE issue_id IN (%s)`, batchInClause),
batchArgs...); err != nil {
return nil, fmt.Errorf("delete leases: %w", err)
}
}
result.DeletedCount = totalRegularsDeleted + len(set.WispIDs)
// Journal every regular issue this bulk/cascade delete removed. Wisps went
// through deleteIssueRowInTx above, which journals each itself; set.All is
// cascade-expanded, so this records cascade deletes too. The delete
// plumbing carries no actor, so the rows record none.
for _, id := range journaledDeletes {View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped driver error (lock timeout, too many parameters, connection reset)
- Reduce delete set size or retry when the DB is not contended
- For SQLite busy errors, raise the busy timeout / close other writers
- Ensure the schema is migrated before deleting
Example fix
// before
result, err := tx.ExecContext(ctx, fmt.Sprintf(`DELETE FROM issues WHERE id IN (%s)`, batchInClause), batchArgs...)
if err != nil { return nil, fmt.Errorf("delete issues: %w", err) }
// after — same error path; avoid busy-lock by configuring the driver
// e.g. dsn := "file:beads.db?_busy_timeout=5000" Defensive patterns
Strategy: try-catch
Validate before calling
// confirm target IDs exist and the DB is writable before the bulk delete
if err := db.PingContext(ctx); err != nil { return err }
// optionally: verify no other process holds a write lock (SQLite) Try / catch
if _, err := DeleteIssuesInTx(ctx, tx, ids, opts); err != nil {
if strings.Contains(err.Error(), "delete issues: ") {
log.Printf("batch DELETE failed: %v", err) // inspect wrapped driver error
}
return err
} Prevention
- Split very large delete sets into smaller calls to avoid driver parameter limits
- Raise SQLite busy timeout or serialize writers
- Apply schema migrations before running new binaries against old DBs
When it happens
Trigger: DeleteIssuesInTx/DeleteInTx executing a cascade or bulk delete where the DELETE statement fails — too many parameters for the driver, table lock/timeout, or connection loss during tx.ExecContext.
Common situations: Very large batch deletes exceeding driver parameter limits on some engines; database locked by another writer (SQLite busy); network interruption to a remote Dolt server.
Related errors
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to remove federation peer: %w
- failed to batch delete wisps: %w
- db: LabelSQLRepository.Delete %s/%s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a21ea774d52f2335.
Report an issue: GitHub.