gastownhall/beads · error
failed to resolve claim pools: %w
Error message
failed to resolve claim pools: %w
What it means
ClaimIssueInTx resolves claim pool aliases (pool pseudo-assignees like 'fable-crew' that any actor may claim through) via ClaimPoolAliasesInTx; failure is wrapped as "failed to resolve claim pools: %w". Pools enable dispatcher pre-assignment; without resolving them the pool-aware CAS cannot be built. The error means reading the claim.pools config from the DB failed.
Source
Thrown at internal/storage/issueops/claim.go:77
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 last
// membership test is deliberately exact-string, unlike actorMatches right
// beside it: a pool alias (e.g. "fable-crew") is a literal claim.pools
// config value, not a Gas Town identity that gets respelled per layer, so
// there is no cross-spelling variant to reconcile — canonicalizing it
// could only blur two administratively-distinct pool names into one.
assigneeOK := oldIssue.Assignee == "" || actorMatches(oldIssue.Assignee, actor) || slices.Contains(pools, oldIssue.Assignee)
// Conditional UPDATE: only attempted while the issue was still claimable
// as of oldIssue, and even then CASed on row_lock rather than re-checking
// assignee/status in SQL — row_lock is rewritten by every path thatView on GitHub (pinned to 71377f2769)
Solutions
- Migrate/upgrade the database so the pool-alias config storage exists.
- Retry the claim transaction if the wrapped error is transient (connection/lock).
- Validate the claim.pools config (remove malformed entries) and re-check with bd doctor.
- Check the wrapped error text to distinguish missing-table (migrate) vs timeout (contention).
Defensive patterns
Strategy: retry
Validate before calling
if err := validatePoolsConfig(cfg.Claim.Pools); err != nil {
return fmt.Errorf("invalid claim.pools config: %w", err)
} Try / catch
if err != nil {
tx.Rollback()
return retry(fmt.Errorf("claim pool resolution failed: %w", err))
} Prevention
- Keep bd upgraded so pool config storage is migrated.
- Validate claim.pools entries (valid assignee names) before dispatching.
- Use backoff-retries for pool resolution errors in high-throughput dispatchers.
- Avoid manual edits to pool configuration storage.
When it happens
Trigger: Claiming when: the pool configuration storage is missing or unreadable, the transaction is aborted by an earlier error, the context is cancelled, or the connection fails during the config SELECT.
Common situations: Older databases without the claim-pool config storage; malformed claim.pools configuration after manual editing; dispatcher loops hitting transient DB errors under load.
Related errors
- db: Claim %s: resolve claim pools: %w
- failed to resolve claimable statuses: %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/cf7036d312d1235d.
Report an issue: GitHub.