gastownhall/beads · error
failed to resolve claimable statuses: %w
Error message
failed to resolve claimable statuses: %w
What it means
Before claiming, ClaimIssueInTx resolves which statuses are claimable ('open' plus configured custom statuses whose category is 'active') via ClaimableSourceStatusesInTx; failure is wrapped as "failed to resolve claimable statuses: %w". This keeps custom-status lifecycle configs (e.g. draft->ready->in_progress) claim-aware while preserving anti-steal protection. The error means reading the status configuration from the DB failed.
Source
Thrown at internal/storage/issueops/claim.go:67
return nil, fmt.Errorf("failed to get issue for claim: %w", err)
}
now := time.Now().UTC()
// Rewrite row_lock with the claim (see lease.go): a concurrent reclaim or
// close on the same row is forced to conflict rather than silently
// cell-merge. The lease itself is granted separately below, in the
// ephemeral leases table — claims commit (status/assignee are
// history-worthy) but lease grants and heartbeats do not (bd-lrgn1).
rowLockClause, rowLockArgs := RowLockClause()
// An issue is claimable from "open" plus any configured custom status whose
// category is "active" (e.g. a draft->ready->in_progress lifecycle where
// "ready" should be claimable). WIP/done/frozen customs are excluded so the
// anti-steal protection from GH-3570 is preserved.
claimableStatuses, err := ClaimableSourceStatusesInTx(ctx, tx)
if err != nil {
return nil, fmt.Errorf("failed to resolve claimable statuses: %w", err)
}
statusPlaceholders, statusArgs := buildSQLInClause(claimableStatuses)
// Pool-aware claim (bd-bguz6): a dispatcher may pre-assign issues to a
// pool pseudo-assignee (e.g. "fable-crew"). Aliases listed in the
// claim.pools config are claimable by any actor through the same CAS;
// issues assigned to a real actor keep their anti-steal protection.
pools, err := ClaimPoolAliasesInTx(ctx, tx)
if err != nil {
return nil, fmt.Errorf("failed to resolve claim pools: %w", err)
}
// Claimability of the assignee slot, judged in Go against oldIssue (the
// pre-image read above, inside this same transaction) rather than as a
// spelling-sensitive SQL predicate (ga-v2k49, same shape as ga-5ksp5's
// unclaim.go fix): empty/unassigned, already this actor — including an
// idempotent re-claim spelled under a different layer's separator
// convention (ga-wzl83) — or assigned to a claim-pool alias. That lastView on GitHub (pinned to 71377f2769)
Solutions
- Migrate the database so custom-status configuration storage exists.
- Retry the claim; resolution failures from connectivity are transient.
- Inspect the wrapped error for 'no such table' and repair/upgrade the schema (bd doctor).
- Validate custom status config (bd doctor / config check) after manual edits.
Defensive patterns
Strategy: retry
Validate before calling
if err := bdDoctor(); err != nil { return fmt.Errorf("schema/config problem: %w", err) } Try / catch
if err != nil {
tx.Rollback()
return retry(fmt.Errorf("claimable status resolution failed: %w", err))
} Prevention
- Upgrade/migrate bd so custom-status config storage exists.
- Validate custom status configuration after manual edits (bd doctor).
- Retry transient failures in dispatcher claim loops with backoff.
- Do not hand-edit status config tables directly.
When it happens
Trigger: Calling claim paths when: the custom-status config storage is missing/corrupt, the transaction is dead, the context is cancelled, or the SELECT over configured statuses fails.
Common situations: Databases created before custom-status support (missing config table); a hand-edited or corrupt status configuration; transient DB failures during dispatcher claim loops.
Related errors
- db: Claim %s: resolve claim pools: %w
- failed to resolve claim pools: %w
- database %q not found on Dolt server at %s:%d
- failed to open database: %w Hint: %s
- loading status configuration: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/58e862ce4b583302.
Report an issue: GitHub.