ruvnet/ruflo · error · Error
Issue ${input.issueId} is not claimed by ${input.claimantId}
Error message
Issue ${input.issueId} is not claimed by ${input.claimantId} What it means
Thrown by the simple releaseClaim handler when the issue exists and is claimed, but issue.claimedBy !== input.claimantId. The release path requires the caller to be the current holder; any other claimant (including an admin) is rejected at this layer.
Source
Thrown at v3/@claude-flow/claims/src/api/mcp-tools.ts:568
}> {
if (context?.claimsService) {
const result = await context.claimsService.releaseClaim(input);
return {
released: result.released,
issueId: input.issueId,
releasedAt: result.releasedAt,
reason: input.reason,
};
}
// Simple implementation
const issue = issueStore.get(input.issueId);
if (!issue) {
throw new Error(`Issue not found: ${input.issueId}`);
}
if (issue.claimedBy !== input.claimantId) {
throw new Error(`Issue ${input.issueId} is not claimed by ${input.claimantId}`);
}
// Find and update the claim
for (const claim of claimStore.values()) {
if (claim.issueId === input.issueId && claim.claimantId === input.claimantId) {
claim.status = 'released';
claim.lastActivityAt = new Date().toISOString();
}
}
issue.claimedBy = undefined;
return {
released: true,
issueId: input.issueId,
releasedAt: new Date().toISOString(),
reason: input.reason,
};View on GitHub (pinned to 6b01dc5a68)
Solutions
- Pass the exact claimantId that holds the claim (the value in issue.claimedBy).
- If you need to transfer, use requestHandoff rather than release+claim.
- For administrative release, use a privileged service method rather than this MCP handler.
Example fix
// before
await releaseClaim.handler({ issueId, claimantId: 'agent-v2' }); // throws 69, holder is 'agent-v1'
// after
const issue = issueStore.get(issueId);
await releaseClaim.handler({ issueId, claimantId: issue.claimedBy }); Defensive patterns
Strategy: validation
Validate before calling
function isHolder(issue, claimantId) { return !!issue && issue.claimedBy === claimantId; }
if (!isHolder(issueStore.get(input.issueId), input.claimantId)) throw new Error('not the holder'); Type guard
function isHolder(issue, id) { return !!issue && issue.claimedBy === id; } Try / catch
null
Prevention
- Pass the exact claimantId stored in issue.claimedBy.
- Use requestHandoff for ownership transfer rather than release+claim.
When it happens
Trigger: A claimant other than the holder calling release; the holder's ID changed between claim and release (e.g., new agent instance ID); a stale claimantId passed by mistake.
Common situations: An agent restart assigned a new ID but tried to release the old ID's claim; a coordinator trying to release on behalf of a worker without using the handoff flow; copy-paste of the wrong claimant ID.
Related errors
- No active claim found for issue ${input.issueId} by ${input.
- UNAUTHORIZED
- Issue not found: ${input.issueId}
- Issue ${input.issueId} is already claimed by ${issue.claimed
- Issue ${input.issueId} is not stealable or not claimed
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/8d320e7e044581b2.
Report an issue: GitHub.