gastownhall/beads · error
partition delete ids: %w
Error message
partition delete ids: %w
What it means
ResolveDeletionSetInTx wraps a failure from PartitionWispIDsInTx, which sorts the deletion set's ids into wisp rows vs regular issue rows. Every subsequent step depends on this routing, so a failure here aborts the delete. This is an internal lookup (SELECT id FROM each routed table), typically a driver/connection issue.
Source
Thrown at internal/storage/issueops/delete.go:132
// durable half is what made `bd wisp gc` (which hardcodes cascade) silently
// under-delete. It does not read the caller's slice destructively either: the
// non-cascade set is a copy, because DeleteRequest promises IDs is never
// sorted in place.
func ResolveDeletionSetInTx(ctx context.Context, tx DBTX, ids []string, cascade bool) (DeletionSet, error) {
all := append([]string(nil), ids...)
if cascade {
closure, err := FindAllDependentsInTx(ctx, tx, ids)
if err != nil {
return DeletionSet{}, fmt.Errorf("expand cascade: %w", err)
}
all = workapi.SortedDeleteIDs(closure)
}
if len(all) == 0 {
return DeletionSet{}, nil
}
wispIDs, regularIDs, err := PartitionWispIDsInTx(ctx, tx, all)
if err != nil {
return DeletionSet{}, fmt.Errorf("partition delete ids: %w", err)
}
return DeletionSet{WispIDs: wispIDs, RegularIDs: regularIDs, All: all}, nil
}
func DeleteIssuesInTx(ctx context.Context, tx *sql.Tx, ids []string, cascade bool, force bool, dryRun bool) (*types.DeleteIssuesResult, error) {
if len(ids) == 0 {
return &types.DeleteIssuesResult{}, nil
}
set, err := ResolveDeletionSetInTx(ctx, tx, ids, cascade)
if err != nil {
return nil, err
}
var orphaned []string
if !cascade {
// The guard here is the STORAGE SEAM's, and it stays durable-only: the
// server-backed store peels wisps off before it ever reaches thisView on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped driver error for the root cause.
- Retry the delete with a fresh transaction and sufficient context lifetime — bulk deletes are long; size the timeout to the id count.
- Run schema migration if a routed table is reported missing.
- Split very large bulk deletes into smaller batches.
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return fmt.Errorf("context expired before delete: %w", err) } Try / catch
if err != nil {
if isTransientDBError(err) { /* retry bulk delete in a fresh tx */ }
return err
} Prevention
- Budget context time proportional to the number of ids in a bulk delete.
- Split large bulk deletes into smaller batches.
- Run migrations after upgrades so routed tables exist.
When it happens
Trigger: Any delete (DeleteIssuesInTx/DeleteInTx, including cascade flows) when the wisp-partition query fails after the id list is built: context canceled, connection dropped, or SQL error on the routed tables.
Common situations: Long-running bulk deletes whose context expired before partitioning; database lock/availability problems; rare schema mismatch where a routed table is absent.
Related errors
- failed to close issue: %w
- affected by delete for %s: %w
- journal dependency removals for %s: %w
- recompute is_blocked after delete for %s: %w
- ErrTransaction
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/0ddd7d843ca45944.
Report an issue: GitHub.