gastownhall/beads · error

scanning open beads for references: %w

Error message

scanning open beads for references: %w

What it means

After resolving custom statuses, sweepReferencedInTx searches all not-done issues (per the reference-scan filter) via SearchIssuesInTx to find beads that might cite the sweep candidates; a failure is wrapped as 'scanning open beads for references'. Note this same message also wraps the comment-fetch failure (error 3808), so the inner error must be read to tell which leg failed.

Source

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

// status would under-protect and delete a bead a live bead still cites
// (issueops.SweepRequest.ProtectReferenced).
func sweepReferencedInTx(ctx context.Context, tx *sql.Tx, candidates []*types.Issue) (map[string]bool, error) {
	if len(candidates) == 0 {
		return nil, nil
	}
	candidateIDs := make(map[string]bool, len(candidates))
	for _, issue := range candidates {
		candidateIDs[issue.ID] = true
	}
	matcher := workapi.NewCandidateIDMatcher(candidateIDs)

	custom, err := ResolveCustomStatusesDetailedInTx(ctx, tx)
	if err != nil {
		return nil, fmt.Errorf("reading custom statuses for reference scan: %w", err)
	}
	notDone, err := SearchIssuesInTx(ctx, tx, "", workapi.BuildSweepReferenceScanFilter(custom))
	if err != nil {
		return nil, fmt.Errorf("scanning open beads for references: %w", err)
	}

	notDoneIDs := make([]string, 0, len(notDone))
	for _, issue := range notDone {
		if issue != nil {
			notDoneIDs = append(notDoneIDs, issue.ID)
		}
	}
	comments, err := GetCommentsForIssuesInTx(ctx, tx, notDoneIDs)
	if err != nil {
		return nil, fmt.Errorf("scanning open beads for references: %w", err)
	}

	referenced := make(map[string]bool)
	for _, issue := range notDone {
		if issue == nil {
			continue
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped inner error to identify the failing leg (this search vs. the comments fetch).
  2. Retry the sweep with a fresh transaction — both legs are read-only up to this point.
  3. Narrow the sweep (fewer candidates, tighter closed-before) to reduce scan cost if timing out.
  4. Verify schema/migrations are current, especially anything touched by the reference-scan filter.

Example fix

// before
result, err := SweepInTx(ctx, tx, req) // reference scan fails mid-run
// after
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()
result, err = SweepInTx(ctx, tx, req) // generous timeout for large scans
Defensive patterns

Strategy: retry

Try / catch

result, err := issueops.SweepInTx(ctx, tx, req)
if err != nil && strings.Contains(err.Error(), "scanning open beads for references") {
    // read-only leg failed; reopen tx, back off, retry
    return fmt.Errorf("reference scan failed, sweep aborted safely: %w", err)
}

Prevention

When it happens

Trigger: SearchIssuesInTx fails while building the not-done set: missing issues table/columns, invalid SQL from BuildSweepReferenceScanFilter with unusual custom statuses, dropped connection, or cancelled context during a ProtectReferenced sweep.

Common situations: Sweeping a large workspace where the open-beads scan times out; Dolt server restart mid-sweep; custom statuses producing an unexpected filter clause; schema drift after an upgrade.

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/4969ac79edb6c680. Report an issue: GitHub.