redis/node-redis · error · Error
All replies must be array of numbers for logical AND aggrega
Error message
All replies must be array of numbers for logical AND aggregation
What it means
The `agg_logical_and` response reducer validates that every shard reply is an array of numbers (e.g. SCRIPT EXISTS returns [0,1,...] per shard) before folding column-wise. If any shard returned something that is not an Array<number>, the reducer refuses to aggregate rather than produce a silently-wrong boolean fold. This guards the runtime shape because the generic type parameter is ergonomics-only and the real input is validated at runtime.
Source
Thrown at packages/client/lib/cluster/request-response-policies/generic-aggregators.ts:19
/**
* Aggregates multiple arrays of numbers using logical AND operation.
* @remarks
* This implementation is specifically designed for Array<Array<number>> type only,
* despite the generic type parameter. It is currently used by the SCRIPT EXISTS command
* which returns an array of 0s and 1s from each shard.
* The generic type parameter T is provided for usage ergonomy, but the actual input structure
* will be validated at runtime.
*/
export const aggregateLogicalAnd = <T>(replies: Array<unknown>): T => {
if (replies.length === 0) return [] as T;
if (
!replies.every(
(reply): reply is number[] =>
Array.isArray(reply) &&
reply.every((value): value is number => typeof value === 'number')
)
) {
throw new Error(
'All replies must be array of numbers for logical AND aggregation'
);
}
const result = Array(replies[0].length).fill(1);
for (const reply of replies) {
for (let i = 0; i < reply.length; i++) {
// clamp to 0/1: `&&` returns the operand, so non-binary replies would
// otherwise leak through (e.g. 1 && 2 === 2).
result[i] = result[i] && reply[i] ? 1 : 0;
}
}
return result as T;
};
/**View on GitHub (pinned to bb5beb5657)
Solutions
- Check the Redis version parity across nodes — SCRIPT EXISTS reply shape must be consistent cluster-wide.
- Inspect per-node replies by running SCRIPT EXISTS against each master directly to find the offending shape.
- Avoid custom typeMapping entries that convert numbers to non-numbers for commands that aggregate.
- Report a metadata/reply-shape regression if shapes diverge across versions.
Defensive patterns
Strategy: try-catch
Type guard
function isNumberArray(reply: unknown): reply is number[] {
return Array.isArray(reply) && reply.every(v => typeof v === 'number');
} Try / catch
try {
await cluster.sendCommand(['SCRIPT', 'EXISTS', sha1, sha2]);
} catch (e) {
if (/array of numbers for logical AND/.test(e.message)) {
// a shard returned a non-conforming reply — check version parity / node health
} else throw e;
} Prevention
- Keep Redis versions uniform across the cluster so SCRIPT EXISTS replies share a shape.
- Avoid custom typeMapping entries that convert numbers to non-numbers for aggregated commands.
- Monitor node health — error replies from a failing node can surface here.
When it happens
Trigger: A fan-out command tagged `agg_logical_and` (currently SCRIPT EXISTS) where at least one node's reply is null, a non-array, or an array containing non-number elements. The dispatch already strips the caller's NUMBER typeMapping for numeric aggregators, so a plain `NUMBER: String` mapping will not cause this — the cause is a genuine shape change or an error reply leaking through.
Common situations: A Redis version where SCRIPT EXISTS returns a different reply shape on some node; a node returning an error that a custom typeMapping transformed into a non-number; mixing RESP2 and RESP3 nodes in a degraded cluster; a module reply-shape change after an upgrade.
Related errors
- 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
- All replies must be numbers for sum aggregation
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/2719b80d3c4fdb7d.json.
Report an issue: GitHub.