ruvnet/ruflo · error · ClaimOperationError
NOT_CLAIMED
NOT_CLAIMED
Error message
Issue ${issueId} is not claimed What it means
Thrown by ClaimService.release when claimRepository.findByIssueId(issueId) returns null/undefined. This is the application-layer equivalent of the MCP 'Issue not found' on release, but in the DDD service. Code is NOT_CLAIMED, distinguishing 'nothing to release' from 'wrong owner'.
Source
Thrown at v3/@claude-flow/claims/src/application/claim-service.ts:247
reviewers: [],
};
// Save claim
await this.claimRepository.save(claim);
// Emit event
const event = createClaimCreatedEvent(claimId, issueId, claimant);
await this.eventStore.append(event);
return { success: true, claim };
}
async release(issueId: string, claimant: Claimant): Promise<void> {
const claim = await this.claimRepository.findByIssueId(issueId);
// Validate claim exists
if (!claim) {
throw new ClaimOperationError('NOT_CLAIMED', `Issue ${issueId} is not claimed`);
}
// Validate claimant owns the claim
if (claim.claimant.id !== claimant.id) {
throw new ClaimOperationError(
'UNAUTHORIZED',
`Claimant ${claimant.name} does not own the claim on issue ${issueId}`
);
}
// Check for pending handoffs
const pendingHandoff = claim.handoffChain?.find((h) => h.status === 'pending');
if (pendingHandoff) {
throw new ClaimOperationError(
'HANDOFF_PENDING',
`Cannot release claim with pending handoff to ${pendingHandoff.to.name}`
);
}View on GitHub (pinned to 6b01dc5a68)
Solutions
- Make release idempotent: catch NOT_CLAIMED and treat as success if already-released is acceptable.
- Confirm the claim exists via findByIssueId before calling release.
- Ensure the same repository instance is used across claim and release.
Example fix
// before
await service.release(issueId, claimant); // throws NOT_CLAIMED
// after
try {
await service.release(issueId, claimant);
} catch (e) {
if (e instanceof ClaimOperationError && e.code === 'NOT_CLAIMED') return; // already released
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const claim = await claimRepo.findByIssueId(issueId); if (!claim) return; // nothing to release
Type guard
null
Try / catch
try { await service.release(issueId, claimant); } catch (e) {
if (e instanceof ClaimOperationError && e.code === 'NOT_CLAIMED') return;
throw e;
} Prevention
- Make release idempotent by swallowing NOT_CLAIMED when that fits your semantics.
- Use the same repository instance across claim and release.
When it happens
Trigger: Calling service.release on an issueId that has never been claimed, whose claim was already released, or that lives in a different repository instance.
Common situations: Idempotent release retry after success; pointing at the wrong repository (in-memory vs persisted); claim TTL expired and was purged.
Related errors
- UNAUTHORIZED
- HANDOFF_PENDING
- CLAIMANT_NOT_FOUND
- Invalid target format: ${target}. Use agent:<id> or human:<i
- Issue not found: ${input.issueId}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/2e0326b1669b2a7b.
Report an issue: GitHub.