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 this

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped driver error for the root cause.
  2. Retry the delete with a fresh transaction and sufficient context lifetime — bulk deletes are long; size the timeout to the id count.
  3. Run schema migration if a routed table is reported missing.
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/0ddd7d843ca45944. Report an issue: GitHub.