ruvnet/ruflo · error · Error

Cannot select from empty array

Error message

Cannot select from empty array

What it means

secureRandomChoice() picks one uniformly random element of an array via the crypto-backed secureRandomInt(). An empty array has no element to return; rather than yielding undefined (and letting modulo selection run on a zero-length range), it throws this guard immediately.

Source

Thrown at v3/@claude-flow/shared/src/security/secure-random.ts:142

  const maxValid = Math.pow(256, bytesNeeded) - (Math.pow(256, bytesNeeded) % range);

  let randomValue: number;
  do {
    const bytes = randomBytes(bytesNeeded);
    randomValue = bytes.reduce((acc, byte, i) => acc + byte * Math.pow(256, i), 0);
  } while (randomValue >= maxValid);

  return min + (randomValue % range);
}

/**
 * Secure random selection from array
 * @param array Array to select from
 * @returns Random element
 */
export function secureRandomChoice<T>(array: T[]): T {
  if (array.length === 0) {
    throw new Error('Cannot select from empty array');
  }
  return array[secureRandomInt(0, array.length - 1)]!;
}

/**
 * Secure shuffle array (Fisher-Yates with crypto)
 * @param array Array to shuffle
 * @returns New shuffled array
 */
export function secureShuffleArray<T>(array: T[]): T[] {
  const result = [...array];
  for (let i = result.length - 1; i > 0; i--) {
    const j = secureRandomInt(0, i);
    [result[i], result[j]] = [result[j]!, result[i]!];
  }
  return result;
}

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Check array.length > 0 before calling secureRandomChoice.
  2. Fix the upstream producer so the candidate set is non-empty (health checks, config defaults, membership).
  3. Fall back to a known non-empty default list when the primary candidate set is empty.

Example fix

// before
const target = secureRandomChoice(healthyNodes); // throws when healthyNodes is []

// after
if (healthyNodes.length === 0) {
  throw new Error('no healthy nodes available');
}
const target = secureRandomChoice(healthyNodes);
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(candidates) || candidates.length === 0) {
  throw new Error('candidate list must be non-empty');
}
const pick = secureRandomChoice(candidates);

Type guard

function isNonEmpty<T>(a: T[]): a is [T, ...T[]] {
  return a.length > 0;
}

Try / catch

try {
  pick = secureRandomChoice(candidates);
} catch (e) {
  if (e instanceof Error && e.message === 'Cannot select from empty array') {
    pick = fallbackCandidate; // or recompute the candidate set
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Passing [] produced by a filter that matched nothing (e.g. candidate nodes filtered by capability or health); an optional config list that defaulted to empty; an array emptied earlier by pop/splice; choosing from a peers/providers list that was never populated.

Common situations: Random load balancing over a 'healthy nodes' list when every node failed its health check; random secret/token generation configured with an empty charset; consensus or scheduling code choosing from zero candidates after membership removal.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/451eb827addc342d. Report an issue: GitHub.