ruvnet/ruflo · warning · ClaimOperationError

VALIDATION_ERROR

VALIDATION_ERROR

Error message

At least one reviewer is required

What it means

Thrown by requestReview when the reviewers argument is null, undefined, or an empty array. This is pure input validation that runs before any repository lookup, so it indicates a caller bug, not a system state problem.

Source

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

      issueId,
      previousStatus,
      status,
      note
    );
    await this.eventStore.append(statusEvent);
  }

  async requestReview(issueId: string, reviewers: 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 at least one reviewer
    if (!reviewers || reviewers.length === 0) {
      throw new ClaimOperationError('VALIDATION_ERROR', 'At least one reviewer is required');
    }

    // Validate reviewers exist
    for (const reviewer of reviewers) {
      const exists = await this.claimantRepository.exists(reviewer.id);
      if (!exists) {
        throw new ClaimOperationError(
          'CLAIMANT_NOT_FOUND',
          `Reviewer ${reviewer.name} not found`
        );
      }
    }

    // Update claim
    const previousStatus = claim.status;
    claim.reviewers = reviewers;
    claim.status = 'in_review';
    claim.lastActivityAt = new Date();

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Guard the call site: only invoke requestReview when reviewers && reviewers.length > 0.
  2. Fall back to a known default reviewer when the computed list is empty.
  3. If no reviewers are available, skip the review stage or surface a configuration error upstream.
  4. Add a unit test asserting reviewers is non-empty at the boundary.

Example fix

// before
await claimService.requestReview(issueId, reviewersFromQuery); // [] -> throws

// after
if (reviewersFromQuery && reviewersFromQuery.length > 0) {
  await claimService.requestReview(issueId, reviewersFromQuery);
} else {
  throw new Error('No reviewers available; refusing to request review');
}
Defensive patterns

Strategy: validation

Validate before calling

if (!reviewers || reviewers.length === 0) {
  throw new Error('Cannot request review: reviewers list is empty');
}
await claimService.requestReview(issueId, reviewers);

Type guard

function hasReviewers(list: Claimant[] | null | undefined): list is Claimant[] {
  return Array.isArray(list) && list.length > 0;
}

Try / catch

try {
  await claimService.requestReview(issueId, reviewers);
} catch (e) {
  if (e instanceof ClaimOperationError && e.code === 'VALIDATION_ERROR') {
    // surface as a 400 to the caller; this is a caller bug, not transient
    throw new BadRequestError(e.message);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing [] or undefined as reviewers; a filter/compute step upstream reduced the reviewer list to zero entries before the call.

Common situations: Reviewer list computed from a query that returned no matches; optional parameter left unset; refactoring that changed the reviewers source.

Related errors


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