gastownhall/beads · error
db: Claim %s: resolve claimable statuses: %w
Error message
db: Claim %s: resolve claimable statuses: %w
What it means
This error wraps a failure of ClaimableSourceStatusesInTx, which resolves the statuses an issue may be claimed from ("open" plus custom active-category statuses) inside the Claim transaction. It prevents hardcoding status='open'; if the lookup fails, Claim aborts with this wrapped error.
Source
Thrown at internal/storage/domain/db/issue.go:442
if err != nil {
return domain.ClaimRowResult{}, fmt.Errorf("db: Claim %s: resolve claim pools: %w", id, err)
}
// Claimability of the assignee slot, judged in Go against oldIssue rather
// than as a spelling-sensitive SQL predicate (ga-v2k49, mirroring the
// same-day fix to issueops.ClaimIssueInTx — this dual must stay in
// lockstep, per the comment above): empty/unassigned, already this actor
// — including a spelling difference across layers (ga-wzl83) — or a
// claim-pool alias. issueops.ActorMatches is the exported form of the
// primary path's package-local actorMatches, kept for exactly this dual.
assigneeOK := oldIssue.Assignee == "" || issueops.ActorMatches(oldIssue.Assignee, actor) || slices.Contains(pools, oldIssue.Assignee)
// Same lockstep for the source statuses (bd-pq7m2): claimable from "open"
// plus custom active-category statuses, like the primary path — not a
// hardcoded status = 'open'.
claimableStatuses, err := issueops.ClaimableSourceStatusesInTx(ctx, r.runner)
if err != nil {
return domain.ClaimRowResult{}, fmt.Errorf("db: Claim %s: resolve claimable statuses: %w", id, err)
}
statusPredicate := "status = ?"
statusArgs := []any{claimableStatuses[0]}
for _, st := range claimableStatuses[1:] {
statusPredicate += " OR status = ?"
statusArgs = append(statusArgs, st)
}
// Conditional UPDATE, attempted only while assigneeOK — otherwise there
// is nothing this actor could win, so skip straight to the rows==0
// disambiguation below (matches the primary path's ga-v2k49 fix). CASed
// on row_lock rather than re-checking assignee in SQL: row_lock is
// rewritten by every path that mutates status/assignee/started_at (see
// the freshRowLock invariant in issueops/lease.go), so requiring it to
// still equal oldIssue.RowVersion detects a race exactly as precisely as
// the old assignee predicate did, without embedding a spelling-sensitive
// string comparison in SQL.
var rows int64View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause (%w) for the underlying SQL/driver error.
- Verify custom status definitions exist and the statuses storage is intact.
- Re-run migrations to restore expected status configuration schema.
- Retry once the database is reachable.
Example fix
// before // statuses config manually emptied; Claim fails resolving statuses // after bd doctor // verify DB integrity, restore statuses config, retry claim
Defensive patterns
Strategy: validation
Validate before calling
// confirm the issue is in a claimable status before attempting
issue, _ := store.Get(ctx, id, opts)
if issue.Status != "open" && issue.Status.Category() != types.CategoryInProgress {
return fmt.Errorf("issue %s not claimable (status=%s)", id, issue.Status)
} Type guard
func claimableStatus(st types.Status) bool {
return st == "open" || st.Category() == types.CategoryActive
} Try / catch
_, err := store.Claim(ctx, id, actor, opts)
if err != nil && strings.Contains(err.Error(), "resolve claimable statuses") {
return fmt.Errorf("status config unreadable; run migrations/bd doctor: %w", err)
} Prevention
- Do not delete custom status definitions without migrating dependent issues.
- Re-run migrations after version upgrades.
- Check status configuration with bd doctor before bulk claims.
- Pre-check issue status in Go to avoid avoidable claim attempts.
When it happens
Trigger: Calling Claim when the SQL resolving claimable source statuses fails: connection error, aborted transaction, missing status configuration storage, context cancellation.
Common situations: Custom status definitions removed or corrupted after manual DB edits; schema drift between versions; transient database outages during a claim.
Related errors
- db: Claim %s: read old issue: %w
- db: Claim %s: resolve claim pools: %w
- db: Claim %s: %w
- db: Claim %s: read current state: %w
- db: Claim %s: record event: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/07b9614ea08209ff.
Report an issue: GitHub.