ruvnet/ruflo · error
selfConsistency: aggregator='mean' requires every sample to
Error message
selfConsistency: aggregator='mean' requires every sample to be a finite number
What it means
When aggregator is 'mean', selfConsistency() reduces all N samples numerically and requires every sample to be a finite number; one bad sample out of N aborts the aggregation. Non-numbers (strings, undefined, null, objects) and non-finite numbers (NaN, Infinity, -Infinity) are all rejected via an every() check before the mean/variance computation.
Source
Thrown at v3/@claude-flow/neural/src/utils/self-consistency.ts:102
// arrays). Float32Array does NOT JSON-encode losslessly by default —
// callers wanting f32 majority should pre-convert via Array.from.
const counts = new Map<string, { value: T; count: number }>();
for (const s of samples) {
const key = canonicalKey(s);
const existing = counts.get(key);
if (existing) existing.count += 1;
else counts.set(key, { value: s, count: 1 });
}
let best: { value: T; count: number } = { value: samples[0], count: 0 };
for (const c of counts.values()) {
if (c.count > best.count) best = c;
}
finalAnswer = best.value;
agreement = best.count / samples.length;
} else if (aggregator === 'mean') {
const nums = samples as unknown as number[];
if (!nums.every((v) => typeof v === 'number' && Number.isFinite(v))) {
throw new Error("selfConsistency: aggregator='mean' requires every sample to be a finite number");
}
const mean = nums.reduce((a, b) => a + b, 0) / nums.length;
const variance = nums.reduce((s, v) => s + (v - mean) ** 2, 0) / nums.length;
const stddev = Math.sqrt(variance);
const range = Math.max(1e-9, Math.abs(mean) || 1); // avoid div-by-0
finalAnswer = mean as unknown as T;
agreement = Math.max(0, Math.min(1, 1 - stddev / range));
} else {
finalAnswer = samples[0];
agreement = 1;
}
return { finalAnswer, samples, agreement, config };
}
/**
* Canonical-form key for grouping. JSON.stringify is enough for primitives,
* arrays, and plain objects with stable key order. Callers wanting locale-View on GitHub (pinned to fa13ee4ad6)
Solutions
- Normalize inside the operation: coerce with Number(x) and check Number.isFinite, or throw your own domain error instead of letting a non-number flow through
- Filter or replace failed samples (e.g. resolve to a sentinel you drop) before they reach the aggregator
- Switch aggregator to 'majority' when outputs are not strictly numeric
- Add a unit test asserting the operation always returns finite numbers
Example fix
// before
await selfConsistency(() => model.sample(), { N: 5, aggregator: 'mean' });
// after
await selfConsistency(async () => {
const out = await model.sample();
const n = Number(out.score);
if (!Number.isFinite(n)) throw new RangeError('sample is not a finite number');
return n;
}, { N: 5, aggregator: 'mean' }); Defensive patterns
Strategy: type-guard
Validate before calling
// make the operation itself safe so every sample is a finite number
const safeOp = async () => {
const out = await operation();
const n = Number(out);
if (!Number.isFinite(n)) throw new RangeError('sample is not a finite number');
return n;
};
await selfConsistency(safeOp, { N: 5, aggregator: 'mean' }); Type guard
function isFiniteNumber(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v);
} Try / catch
try {
await selfConsistency(op, { N, aggregator: 'mean' });
} catch (e) {
if (String(e).includes("aggregator='mean'")) {
// fall back to majority vote over the same samples
await selfConsistency(op, { N, aggregator: 'majority' });
} else {
throw e;
}
} Prevention
- Use 'mean' only when the operation is contractually numeric
- Coerce and check Number.isFinite inside the operation
- Filter failed samples out before aggregation
- Add a type test asserting the operation returns finite numbers
When it happens
Trigger: The operation returns mixed types — a number on success but a string or undefined on a parse failure or missing field; a model call that occasionally yields NaN after Number('N/A'); a division-by-zero branch leaking Infinity into one sample.
Common situations: Applying 'mean' to LLM/model outputs without normalizing them to numbers first; aggregation configs copied from a majority-vote use case; samples drawn from heterogeneous optional fields.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/21d5cea56566a5fa.
Report an issue: GitHub.