gastownhall/beads · error

listing sweep candidates: %w

Error message

listing sweep candidates: %w

What it means

SweepInTx lists sweep candidates by delegating to SearchIssuesInTx with a filter built from the SweepRequest; a failure there is wrapped as 'listing sweep candidates'. This aborts the whole `bd purge`/`bd prune` sweep before anything is deleted, so no data loss occurs from this error itself.

Source

Thrown at internal/storage/issueops/sweep.go:36

// package because the work is several reads and a write that must see one
// snapshot, and storage.DoltStorage publishes methods, not transactions. The
// two Dolt-backed stores share this body, so they are ONE vote and the
// unit-of-work provider is the second.
//
// It assumes a request already refused by workapi.ValidateSweepRequest. The
// accessors validate BEFORE opening a transaction, so a refusal costs no
// database work.
//
// WHAT ONE TRANSACTION GIVES UP: the server-backed store's own DeleteIssues
// splits large wisp deletions into batched transactions to stay inside Dolt's
// write timeout, and a sweep cannot both do that and promise that the set it
// counted is the set it deleted. It promises the latter.
func SweepInTx(ctx context.Context, tx *sql.Tx, req publicops.SweepRequest) (publicops.SweepResult, error) {
	result := publicops.SweepResult{DryRun: req.DryRun}

	candidates, err := SearchIssuesInTx(ctx, tx, "", workapi.BuildSweepCandidateFilter(req))
	if err != nil {
		return publicops.SweepResult{}, fmt.Errorf("listing sweep candidates: %w", err)
	}

	kept, skips := workapi.FilterSweepCandidates(candidates, req.IDPattern, req.ClosedBefore)
	result.Skipped = skips

	if req.ProtectReferenced {
		referenced, err := sweepReferencedInTx(ctx, tx, kept)
		if err != nil {
			return publicops.SweepResult{}, err
		}
		var count int
		kept, count, result.ReferencedIDs = workapi.PartitionSweepReferenced(kept, referenced)
		result.Skipped.Referenced = count
	}

	if len(kept) == 0 {
		return result, nil
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped inner error from SearchIssuesInTx for the root cause (missing table, cancelled context, syntax).
  2. Re-run the sweep in dry-run mode after confirming the database is reachable and migrations are current.
  3. Reduce sweep scope (narrower --before date or ID pattern) if the candidate query times out.
  4. Retry with a fresh transaction — candidate listing is read-only and safe to retry.

Example fix

// before
result, err := SweepInTx(ctx, tx, req) // candidate query fails
// after
if err := store.Migrate(ctx); err != nil { return err } // ensure schema intact
result, err = SweepInTx(ctx, tx, req)
Defensive patterns

Strategy: try-catch

Try / catch

result, err := issueops.SweepInTx(ctx, tx, req)
if err != nil && strings.Contains(err.Error(), "listing sweep candidates") {
    // nothing deleted yet — safe to fix connection/schema and retry
    return fmt.Errorf("sweep aborted before deletion: %w", err)
}

Prevention

When it happens

Trigger: SearchIssuesInTx fails because the issues table is missing/locked, the candidate filter produces invalid SQL (e.g. a bad IDPattern-driven clause), the connection drops, or the context is cancelled during the candidate query.

Common situations: Running `bd prune --dry-run` against a database that lost its schema; a Dolt server restart during a sweep; very large candidate sets timing out; corrupted label/dependency tables referenced by the search join.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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