redis/node-redis · error · Error
All replies must be numbers for max aggregation
Error message
All replies must be numbers for max aggregation
What it means
Mirror of agg_min's scalar guard for `agg_max`. The first reply was not an array, so the reducer expects all replies to be plain numbers for Math.max; any non-number reply aborts. Same numeric-mapping strip applies, so the cause is a genuine non-numeric scalar from at least one shard.
Source
Thrown at packages/client/lib/cluster/request-response-policies/generic-aggregators.ts:140
throw new Error('All replies must be numbers for min aggregation');
}
return Math.min(...replies) as T;
};
/**
* Aggregates shard replies by taking the maximum value.
* @remarks
* Mirrors {@link aggregateMin}: scalar replies fold to a single maximum, array
* replies fold element-wise (AGG_MAX semantics). Input structure is validated
* at runtime; the generic `T` is for call-site ergonomy only.
*/
export const aggregateMax = <T>(replies: Array<unknown>): T => {
if (replies.length === 0) return 0 as T;
if (Array.isArray(replies[0])) {
return aggregateElementwise(replies, Math.max, 'max') as T;
}
if (!replies.every((reply): reply is number => typeof reply === 'number')) {
throw new Error('All replies must be numbers for max aggregation');
}
return Math.max(...replies) as T;
};
/**
* Aggregates multiple numbers by finding the sum of all values.
* @remarks
* This implementation is specifically designed for Array<number> type only,
* despite the generic type parameter. The generic type parameter T is provided
* for usage ergonomy, but the actual input structure will be validated at runtime.
*/
export const aggregateSum = <T>(replies: Array<unknown>): T => {
if (replies.length === 0) return 0 as T;
if (!replies.every((reply): reply is number => typeof reply === 'number')) {
throw new Error('All replies must be numbers for sum aggregation');
}
return replies.reduce((acc, reply) => acc + reply, 0) as T;
};View on GitHub (pinned to bb5beb5657)
Solutions
- Identify the offending node by running the command against each master directly.
- Verify Redis version parity.
- Audit custom typeMapping entries affecting the command's RESP types.
Defensive patterns
Strategy: try-catch
Type guard
function allNumbers(replies: unknown[]): replies is number[] {
return replies.every(r => typeof r === 'number');
} Try / catch
try {
await cluster.sendCommand(cmd, ...args);
} catch (e) {
if (/must be numbers for max/.test(e.message)) {
// a shard returned a non-number — isolate the node
} else throw e;
} Prevention
- Verify Redis version consistency across the cluster.
- Isolate the offending node by running the command per-master.
- Audit custom typeMapping entries affecting the command's RESP types.
When it happens
Trigger: A command tagged `agg_max` whose replies are scalars but at least one shard returned a non-number value. As with agg_min, the array path is skipped and the scalar type check fails.
Common situations: Version skew; an error reply leaking through as a non-number; a transformed reply from a custom typeMapping not covered by the numeric-aggregator strip.
Related errors
- All replies must be array of numbers for logical AND aggrega
- All replies must be array of numbers for logical OR aggregat
- All replies must be number arrays of equal length for ${labe
- All replies must be numbers for min aggregation
- All replies must be numbers for sum aggregation
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/432eeaa1afbef427.json.
Report an issue: GitHub.