ruvnet/ruflo · error · ClaimOperationError

CLAIMANT_NOT_FOUND

CLAIMANT_NOT_FOUND

Error message

Target claimant ${to.name} not found

What it means

Thrown by ClaimService.requestHandoff when claimantRepository.findById(to.id) returns null. The service validates the target claimant is registered before creating a handoff record, so an unknown recipient is rejected with CLAIMANT_NOT_FOUND. This prevents handing off to a non-existent agent/human.

Source

Thrown at v3/@claude-flow/claims/src/application/claim-service.ts:321

      throw new ClaimOperationError(
        'UNAUTHORIZED',
        `Claimant ${from.name} does not own the claim on issue ${issueId}`
      );
    }

    // Check for existing pending handoffs
    const existingPending = claim.handoffChain?.find((h) => h.status === 'pending');
    if (existingPending) {
      throw new ClaimOperationError(
        'HANDOFF_PENDING',
        `A handoff to ${existingPending.to.name} is already pending`
      );
    }

    // Validate 'to' claimant exists
    const toClaimant = await this.claimantRepository.findById(to.id);
    if (!toClaimant) {
      throw new ClaimOperationError('CLAIMANT_NOT_FOUND', `Target claimant ${to.name} not found`);
    }

    // Create handoff record
    const handoffId = `handoff-${randomUUID()}`;
    const handoffRecord: HandoffRecord = {
      id: handoffId,
      from,
      to,
      reason,
      status: 'pending',
      requestedAt: new Date(),
    };

    // Update claim
    claim.handoffChain = claim.handoffChain ?? [];
    claim.handoffChain.push(handoffRecord);
    claim.status = 'pending_handoff';
    claim.lastActivityAt = new Date();

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Register the target claimant (claimantRepository.create) before requesting a handoff.
  2. Look up the target via findById first and surface a clear error if missing.
  3. Ensure the same claimant repository instance is used for both registration and handoff.

Example fix

// before
await service.requestHandoff(issueId, from, { id: 'agent-v2', name: 'V2', type: 'agent' }, reason);
// throws CLAIMANT_NOT_FOUND

// after
const to = await claimantRepo.findById('agent-v2');
if (!to) throw new Error('Register agent-v2 first');
await service.requestHandoff(issueId, from, to, reason);
Defensive patterns

Strategy: validation

Validate before calling

const toClaimant = await claimantRepo.findById(to.id);
if (!toClaimant) throw new Error(`claimant ${to.id} not registered`);

Type guard

null

Try / catch

try { await service.requestHandoff(issueId, from, to, reason); } catch (e) {
  if (e instanceof ClaimOperationError && e.code === 'CLAIMANT_NOT_FOUND') { await claimantRepo.create(to); } else throw e;
}

Prevention

When it happens

Trigger: Passing a 'to' Claimant whose id was never registered in the claimant repository; a typo'd id; a target agent that has been decommissioned.

Common situations: Handing off to an agent that hasn't been provisioned yet; referencing a human by the wrong id; the claimant repository is a different instance from the one where the target was created.

Related errors


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