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
- Check array.length > 0 before calling secureRandomChoice.
- Fix the upstream producer so the candidate set is non-empty (health checks, config defaults, membership).
- 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
- Treat an empty candidate set as a domain error where it is produced (health checks, config loading), not at the random call.
- Type lists as non-empty tuples ([T, ...T[]]) where the invariant holds, pushing the check to construction time.
- Log when candidate sets become empty — it usually indicates an upstream failure being masked.
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
- signAttributionArtifact: privateKey must be 32 bytes (got ${
- Encrypted buffer too short: need >= ${minLen}B, got ${buf.le
- Invalid git ref: contains unsafe characters
- Invalid git ref: suspicious pattern
- Invalid git ref: too long
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/451eb827addc342d.
Report an issue: GitHub.