redis/node-redis · error · Error
All replies must be numbers for sum aggregation
Error message
All replies must be numbers for sum aggregation
What it means
The `agg_sum` reducer requires every shard reply to be a number before summing. If any reply is non-numeric (string, null, object), it refuses to aggregate. Used by multi_shard commands like DEL/UNLINK/EXISTS/TOUCH (count of affected keys summed across slots). The dispatcher strips NUMBER typeMapping for numeric aggregators, so the cause is a genuine shape mismatch, not a String-mapped number.
Source
Thrown at packages/client/lib/cluster/request-response-policies/generic-aggregators.ts:155
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;
};
export const aggregateMerge = <T>(replies: Array<unknown>): T => {
if(replies.length === 0) return undefined as T;
const firstReply = replies[0]
if(Array.isArray(firstReply)) {
const set = new Set()
for(const reply of replies) {
for(const item of reply as Array<unknown>) {
set.add(item);
}
}
return Array.from(set) as T;View on GitHub (pinned to bb5beb5657)
Solutions
- Run DEL/UNLINK/EXISTS/TOUCH with keys hashing to a single slot (hash tags) to isolate which shard misbehaves.
- Verify all nodes run the same Redis major/minor.
- Check cluster health — a failing node can return error replies that surface here.
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.del('{a}1', '{b}2', '{c}3');
} catch (e) {
if (/must be numbers for sum/.test(e.message)) {
// a shard returned a non-integer count — check node health/version
} else throw e;
} Prevention
- Use hash tags to isolate multi_shard commands to one slot when diagnosing shape errors.
- Keep Redis versions uniform across the cluster during rolling upgrades.
- Monitor node health — error replies from a failing node can surface as non-number counts.
When it happens
Trigger: A multi_shard command (DEL, UNLINK, EXISTS, TOUCH) or any agg_sum-tagged command where at least one shard's reply is not a number — e.g. a node returned an error reply that wasn't a rejection, or a version where the integer reply changed type.
Common situations: A shard returning an error string instead of an integer count; RESP version mismatch; a module replying with a different type on some node; running against an inhomogeneous cluster during a rolling upgrade.
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 max aggregation
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/d02d5a54745e40f2.json.
Report an issue: GitHub.