gastownhall/beads · error

reading custom statuses for reference scan: %w

Error message

reading custom statuses for reference scan: %w

What it means

This error wraps any failure from GetCustomStatuses while the sweep's reference scan is preparing its filter inside a unit of work. The scan must know which statuses count as 'done' (including user-defined custom statuses) before searching open beads, so a config read failure aborts the whole sweep rather than guessing. The library throws it to preserve the underlying config/storage error while marking the sweep stage that failed.

Source

Thrown at internal/storage/uow/sweeper.go:135

}

// sweepReferencedInUOW returns which of the candidates a not-done row cites,
// reading the not-done set and its comments on the same unit of work the
// candidates came off. Comments are read for the whole not-done set in ONE
// batch rather than one query per row.
func sweepReferencedInUOW(ctx context.Context, uw UnitOfWork, 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 := uw.ConfigUseCase().GetCustomStatuses(ctx)
	if err != nil {
		return nil, fmt.Errorf("reading custom statuses for reference scan: %w", err)
	}
	page, err := uw.IssueUseCase().SearchIssues(ctx, "", workapi.BuildSweepReferenceScanFilter(custom))
	if err != nil {
		return nil, fmt.Errorf("scanning open beads for references: %w", err)
	}
	notDone := page.Items

	notDoneIDs := make([]string, 0, len(notDone))
	for _, issue := range notDone {
		if issue != nil {
			notDoneIDs = append(notDoneIDs, issue.ID)
		}
	}
	// BOTH PLANES, and this is not an optimization detail. The not-done set
	// comes from SearchIssues, which merges the durable and wisp planes, so it
	// contains wisps — and their comments live in wisp_comments, which
	// GetCommentsForIssues does not read. Scanning only the durable table left
	// a closed bead cited solely by a comment on an open WISP unprotected, so

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause (%w) for the actual config/storage failure and fix that first
  2. Re-open the database / retry the sweep once connectivity to the Dolt backend is restored
  3. Verify the .beads database schema is current (run bd's migration/doctor command) and that no older beads version downgraded it
  4. Check filesystem permissions on the database files if using embedded mode
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: check the config store is reachable before sweeping
if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("database unreachable before sweep: %w", err)
}

Type guard

if custom, err := cfgUseCase.GetCustomStatuses(ctx); err != nil {
    var cause *StorageError
    if errors.As(err, &cause) { /* handle storage-level failure */ }
}

Try / catch

result, err := sweeper.Sweep(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "reading custom statuses") {
        // inspect errors.Unwrap(err) / errors.As for the config cause,
        // restore connectivity, then retry the sweep
    }
    return err
}

Prevention

When it happens

Trigger: Calling bd prune/sweep when the underlying config store (dolt `config` tables) is unreadable — e.g. database connection dropped mid-unit-of-work, corrupt or missing config table, or the ConfigUseCase's query fails for a permissions/schema reason.

Common situations: A Dolt server restart or network blip between opening the UOW and reading config; running against a repo whose .beads database was created by an older version lacking the custom-status schema; file-permission problems on the embedded database.

Related errors


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