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

  1. Pass the exact claimantId that holds the claim (the value in issue.claimedBy).
  2. If you need to transfer, use requestHandoff rather than release+claim.
  3. 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

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


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/8d320e7e044581b2. Report an issue: GitHub.