ruvnet/ruflo · error
Issue is already claimed by
Error message
Issue ${input.issueId} is already claimed by ${issue.claimedBy} What it means
Thrown by the claim-issue MCP tool handler in @claude-flow/claims when the issue exists but issue.claimedBy is already set, i.e. another claimant holds an active claim. This is the double-claim guard in the 'Simple implementation' path and fires before a new Claim record is created.
Solutions
- Have the current holder call the release tool (or release with the owner's claimantId) before re-claiming
- If the holder is defunct, use the mark-stealable + steal flow (issue_mark_stealable then issue_steal) to take over the claim
- Query the issue state first and skip claiming when claimedBy is set, treating the issue as taken
- Make claim attempts idempotent per agent: if already claimed by the same claimantId, proceed instead of erroring
Example fix
// before
await claimTool({ issueId, claimantId: 'agent-2', claimantType: 'agent' }); // agent-1 holds it
// after
const issue = await getIssueTool({ issueId });
if (issue.claimedBy && issue.claimedBy !== 'agent-2') {
await markStealableTool({ issueId, claimantId: issue.claimedBy, reason: 'owner unresponsive' });
await stealTool({ issueId, claimantId: 'agent-2', claimantType: 'agent' });
} else {
await claimTool({ issueId, claimantId: 'agent-2', claimantType: 'agent' });
} Defensive patterns
Strategy: validation
Validate before calling
const issue = issueStoreSnapshot.get(issueId); // via get-issue tool
if (issue?.claimedBy && issue.claimedBy !== claimantId) {
return { skipped: true, reason: `taken by ${issue.claimedBy}` };
}
await claimTool({ issueId, claimantId, claimantType }); Try / catch
try { await claimTool(input); } catch (e) { if (e instanceof Error && e.message.includes('is already claimed by')) { const holder = e.message.split('claimed by ')[1]; await coordinateWith(holder); } throw e; } Prevention
- Make claim attempts idempotent per agent (skip when already yours)
- Use stealable/steal for stuck claims instead of re-claiming
- Design workers to claim via a single coordinator to avoid races
When it happens
Trigger: Two agents calling the claim tool for the same issueId concurrently or sequentially while the first claim is still active; retrying a claim after a network timeout when the first attempt actually succeeded; claiming an issue whose prior owner never called release.
Common situations: Multiple swarm workers scanning the same backlog and racing for tasks; at-least-once retry logic in the client duplicating a successful claim; stale claims from crashed agents that never released, permanently blocking the issue.
Related errors
- Issue is not claimed by
- Issue is not stealable or not claimed
- Issue not found
- No active claim found for issue
- Agent has reached max concurrent tasks
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/c38ca0c2e4fc71be.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/claims/src/api/mcp-tools.ts:503
return {
claimId: claim.id,
issueId: claim.issueId,
claimantId: claim.claimantId,
claimantType: claim.claimantType,
status: claim.status,
claimedAt: claim.claimedAt,
expiresAt: claim.expiresAt,
};
}
// Simple implementation
const issue = issueStore.get(input.issueId);
if (!issue) {
throw new Error(`Issue not found: ${input.issueId}`);
}
if (issue.claimedBy) {
throw new Error(`Issue ${input.issueId} is already claimed by ${issue.claimedBy}`);
}
const claimId = generateSecureId('claim');
const claimedAt = new Date().toISOString();
const expiresAt = input.expiresInMs
? new Date(Date.now() + input.expiresInMs).toISOString()
: undefined;
const claim: Claim = {
id: claimId,
issueId: input.issueId,
claimantType: input.claimantType,
claimantId: input.claimantId,
status: 'active',
priority: input.priority || issue.priority,
stealable: false,
claimedAt,
lastActivityAt: claimedAt,View on GitHub (pinned to fa13ee4ad6)