ruvnet/ruflo · error
No active claim found for issue
Error message
No active claim found for issue ${input.issueId} by ${input.claimantId} What it means
Thrown by the issue status-update handler in @claude-flow/claims when no claim in claimStore matches both input.issueId and input.claimantId with an active status. The handler iterates claims looking for the caller's active claim before applying status/progress/notes updates, and throws after the loop finds nothing.
Solutions
- (Re-)claim the issue with the same claimantId before sending status updates
- Verify an active claim exists for (issueId, claimantId) before each update batch
- If the claim was stolen or released, stop updating and restart the task lifecycle from claim
- Use identical claimantId/claimantType values across claim and update calls (store them from the claim response)
Example fix
// before
await statusTool({ issueId, claimantId: 'agent-1', status: 'in_progress' }); // never claimed
// after
await claimTool({ issueId, claimantId: 'agent-1', claimantType: 'agent' });
await statusTool({ issueId, claimantId: 'agent-1', status: 'in_progress' }); Defensive patterns
Strategy: validation
Validate before calling
const claim = await getClaimTool({ issueId });
if (!claim || claim.claimantId !== claimantId || claim.status !== 'active') {
await claimTool({ issueId, claimantId, claimantType });
}
await statusTool({ issueId, claimantId, status, progress }); Try / catch
try { await statusTool(input); } catch (e) { if (e instanceof Error && e.message.startsWith('No active claim found')) { await claimTool({ issueId: input.issueId, claimantId: input.claimantId, claimantType }); return statusTool(input); } throw e; } Prevention
- Send status updates only between claim and release in the task lifecycle
- Reuse the claimantId/claimantType from the claim response verbatim
- Re-claim after worker restarts before resuming updates
When it happens
Trigger: Calling the status-update tool before ever claiming the issue; calling it after the claim was released or expired; using a claimantId that differs from the one on the existing claim (including claimantType mismatch in the lookup); store restart losing the claim records.
Common situations: Worker restarts that resume progress reporting without re-claiming; agents whose claims were stolen mid-task still posting updates; inconsistent claimant id formatting between claim and update calls.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Issue is already claimed by
- Issue is not claimed by
- Issue is not stealable or not claimed
- Issue not found
- NOT_CLAIMED
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/5cd2dfdf4c7f42cd.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/claims/src/api/mcp-tools.ts:676
// Simple implementation
for (const claim of claimStore.values()) {
if (claim.issueId === input.issueId && claim.claimantId === input.claimantId) {
claim.status = input.status;
claim.lastActivityAt = new Date().toISOString();
if (input.progress !== undefined) {
claim.metadata = { ...claim.metadata, progress: input.progress };
}
return {
issueId: input.issueId,
status: input.status,
progress: input.progress,
updatedAt: claim.lastActivityAt,
notes: input.notes,
};
}
}
throw new Error(`No active claim found for issue ${input.issueId} by ${input.claimantId}`);
}
/**
* List unclaimed issues
*/
async function handleIssueListAvailable(
input: z.infer<typeof issueListAvailableSchema>,
context?: ToolContext
): Promise<{
issues: Issue[];
total: number;
limit: number;
offset: number;
}> {
initializeMockData();
if (context?.claimsService) {
const result = await context.claimsService.listAvailableIssues(input);View on GitHub (pinned to fa13ee4ad6)