gastownhall/beads · warning
ErrNotClaimable
ErrNotClaimable
Error message
issue not claimable
What it means
ErrNotClaimable is returned when attempting to claim an issue that is not in a claimable state, such as closed, deferred, or already in progress without the same actor owning the claim. ClaimConflictError wraps it while carrying the state (assignee and status) that refused the claim, so the sentinel still matches via errors.Is.
Source
Thrown at issueops/errors.go:17
package issueops
import (
"errors"
"fmt"
"github.com/steveyegge/beads/beadserrors"
)
// ErrAlreadyClaimed is returned when attempting to claim an issue that is already
// claimed by another user. The error message contains the current assignee.
var ErrAlreadyClaimed = errors.New("issue already claimed")
// ErrNotClaimable is returned when attempting to claim an issue that is not in a
// claimable state, such as closed, deferred, or already in progress without the
// same actor owning the claim.
var ErrNotClaimable = errors.New("issue not claimable")
// ClaimConflictError reports the state that refused a claim — the current
// assignee and status, read inside the same transaction that lost the
// compare-and-set. It wraps the refusal rather than replacing it, so the
// sentinel still matches, the refusal's carefully-worded prose survives
// byte-for-byte, and a caller can classify the conflict from typed fields
// instead of parsing that prose.
//
// Err is set by every implementation that returns this type; a Claimer whose
// same-transaction re-read fails returns the bare refusal instead.
type ClaimConflictError struct {
// IssueID names the issue that refused the claim.
IssueID string
// Assignee is the holder observed by the losing transaction. It is empty
// when the refusal was about the status rather than a foreign holder.
Assignee string
// Status is the status observed by the losing transaction.
Status StatusView on GitHub (pinned to 71377f2769)
Solutions
- Check the issue's status first (via ClaimConflictError fields or a fresh read) and only claim open/unassigned issues.
- If the issue is in progress and you are the same actor, re-assert your claim rather than a fresh claim.
- Review the configured active/WIP status settings if the refusal state seems wrong for your workflow.
- If the issue is closed or deferred, reopen it (if policy allows) before claiming.
Example fix
// before
err := claimer.Claim(ctx, req) // refused: status=closed
// after
iss, _ := store.GetIssue(ctx, req.ID)
if iss.Status == "open" {
err = claimer.Claim(ctx, req)
} else if errors.Is(err, issueops.ErrNotClaimable) {
var c *issueops.ClaimConflictError
errors.As(err, &c) // c.Status explains the refusal
} Defensive patterns
Strategy: validation
Validate before calling
iss, _ := store.GetIssue(ctx, id)
claimable := iss.Status == "open" || (iss.Status == wipStatus && iss.Assignee == actor)
if !claimable {
return fmt.Errorf("issue %s not claimable (status %s)", id, iss.Status)
} Try / catch
if errors.Is(err, issueops.ErrNotClaimable) {
var c *issueops.ClaimConflictError
errors.As(err, &c) // c.Status explains what refused the claim
} Prevention
- Only claim issues with an open status.
- Review configured active/WIP status settings after config changes.
- Re-read issue state right before claiming to avoid races.
When it happens
Trigger: Claiming an issue whose status is closed, deferred, or a configured WIP/ineligible status (e.g. built-in ineligible statuses or configured active statuses per RunClaimer tests); claiming while progress-status config rejects the transition.
Common situations: Race where the issue was closed between listing and claiming; claiming an issue someone already moved to in_progress; misconfigured active/WIP status lists in config making valid-looking claims refused.
Related errors
- ErrAlreadyClaimed
- ErrNotOwner
- ready claim of %s reported success but could not be verified
- db: Claim %s: read old issue: %w
- db: Claim %s: resolve claim pools: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/617401a61d89f3b6.
Report an issue: GitHub.