{"record":{"id":"c3607af8255c255a","repo":"gastownhall/beads","slug":"listing-sweep-candidates-w","errorCode":null,"errorMessage":"listing sweep candidates: %w","messagePattern":"listing sweep candidates: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/sweep.go","lineNumber":36,"sourceCode":"// package because the work is several reads and a write that must see one\n// snapshot, and storage.DoltStorage publishes methods, not transactions. The\n// two Dolt-backed stores share this body, so they are ONE vote and the\n// unit-of-work provider is the second.\n//\n// It assumes a request already refused by workapi.ValidateSweepRequest. The\n// accessors validate BEFORE opening a transaction, so a refusal costs no\n// database work.\n//\n// WHAT ONE TRANSACTION GIVES UP: the server-backed store's own DeleteIssues\n// splits large wisp deletions into batched transactions to stay inside Dolt's\n// write timeout, and a sweep cannot both do that and promise that the set it\n// counted is the set it deleted. It promises the latter.\nfunc SweepInTx(ctx context.Context, tx *sql.Tx, req publicops.SweepRequest) (publicops.SweepResult, error) {\n\tresult := publicops.SweepResult{DryRun: req.DryRun}\n\n\tcandidates, err := SearchIssuesInTx(ctx, tx, \"\", workapi.BuildSweepCandidateFilter(req))\n\tif err != nil {\n\t\treturn publicops.SweepResult{}, fmt.Errorf(\"listing sweep candidates: %w\", err)\n\t}\n\n\tkept, skips := workapi.FilterSweepCandidates(candidates, req.IDPattern, req.ClosedBefore)\n\tresult.Skipped = skips\n\n\tif req.ProtectReferenced {\n\t\treferenced, err := sweepReferencedInTx(ctx, tx, kept)\n\t\tif err != nil {\n\t\t\treturn publicops.SweepResult{}, err\n\t\t}\n\t\tvar count int\n\t\tkept, count, result.ReferencedIDs = workapi.PartitionSweepReferenced(kept, referenced)\n\t\tresult.Skipped.Referenced = count\n\t}\n\n\tif len(kept) == 0 {\n\t\treturn result, nil\n\t}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/sweep.go#L18-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped inner error from SearchIssuesInTx for the root cause (missing table, cancelled context, syntax).","Re-run the sweep in dry-run mode after confirming the database is reachable and migrations are current.","Reduce sweep scope (narrower --before date or ID pattern) if the candidate query times out.","Retry with a fresh transaction — candidate listing is read-only and safe to retry."],"exampleFix":"// before\nresult, err := SweepInTx(ctx, tx, req) // candidate query fails\n// after\nif err := store.Migrate(ctx); err != nil { return err } // ensure schema intact\nresult, err = SweepInTx(ctx, tx, req)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"result, err := issueops.SweepInTx(ctx, tx, req)\nif err != nil && strings.Contains(err.Error(), \"listing sweep candidates\") {\n    // nothing deleted yet — safe to fix connection/schema and retry\n    return fmt.Errorf(\"sweep aborted before deletion: %w\", err)\n}","preventionTips":["Always dry-run sweeps before real deletion","Ensure schema is migrated before running purge/prune","Narrow sweep scope (ID pattern, closed-before) on large databases","Retry candidate listing on transient connection errors — it's read-only"],"tags":["go","sql","sweep","search"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}