{"record":{"id":"2719b80d3c4fdb7d","repo":"redis/node-redis","slug":"all-replies-must-be-array-of-numbers-for-logical-a","errorCode":null,"errorMessage":"All replies must be array of numbers for logical AND aggregation","messagePattern":"All replies must be array of numbers for logical AND aggregation","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/cluster/request-response-policies/generic-aggregators.ts","lineNumber":19,"sourceCode":"/**\n * Aggregates multiple arrays of numbers using logical AND operation.\n * @remarks\n * This implementation is specifically designed for Array<Array<number>> type only,\n * despite the generic type parameter. It is currently used by the SCRIPT EXISTS command\n * which returns an array of 0s and 1s from each shard.\n * The generic type parameter T is provided for usage ergonomy, but the actual input structure\n * will be validated at runtime.\n */\nexport const aggregateLogicalAnd = <T>(replies: Array<unknown>): T => {\n  if (replies.length === 0) return [] as T;\n  if (\n    !replies.every(\n      (reply): reply is number[] =>\n        Array.isArray(reply) &&\n        reply.every((value): value is number => typeof value === 'number')\n    )\n  ) {\n    throw new Error(\n      'All replies must be array of numbers for logical AND aggregation'\n    );\n  }\n\n  const result = Array(replies[0].length).fill(1);\n\n  for (const reply of replies) {\n    for (let i = 0; i < reply.length; i++) {\n      // clamp to 0/1: `&&` returns the operand, so non-binary replies would\n      // otherwise leak through (e.g. 1 && 2 === 2).\n      result[i] = result[i] && reply[i] ? 1 : 0;\n    }\n  }\n\n  return result as T;\n};\n\n/**","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/cluster/request-response-policies/generic-aggregators.ts#L1-L37","documentation":"Thrown by the agg_logical_and response reducer when at least one shard's reply is not an array of numbers. This policy is used by SCRIPT EXISTS (all_shards request policy), where each shard returns an array of 0/1 indicating script presence. The numeric aggregation pipeline strips type mappings before execution, so a NUMBER:String mapping should not trigger this — the error indicates a shard returned an unexpected reply shape.","triggerScenarios":"SCRIPT EXISTS under cluster mode where one shard returns a non-array reply (e.g. an error that somehow resolved, or a RESP decode that produced a different type); heterogeneous Redis versions where SCRIPT EXISTS returns a different reply shape; one shard in a degraded state returning a malformed RESP reply.","commonSituations":"Mixed Redis server versions across cluster shards; shard returning an unexpected error reply that gets coerced to a non-array; RESP2/RESP3 protocol mismatch between shards.","solutions":["Ensure all cluster nodes run the same Redis version","Check cluster node health — a degraded node may return unexpected replies","Verify no middleware or proxy is altering RESP replies","If using a custom typeMapping, verify it does not affect the NUMBER type in a way that bypasses the numeric-agg stripping"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isLogicalAndAggError(err: unknown): boolean {\n  return err instanceof Error && err.message.includes('logical AND aggregation');\n}","tryCatchPattern":"try {\n  await cluster.scriptExists('sha1', 'sha2');\n} catch (err) {\n  if (err instanceof Error && err.message.includes('logical AND aggregation')) {\n    // likely a shard-level issue — check node health, then retry or fall back\n  } else {\n    throw err;\n  }\n}","preventionTips":["Ensure all cluster nodes run the same Redis version","Monitor shard health — a degraded node may return malformed replies","Verify no middleware alters RESP replies between client and server"],"tags":["cluster","aggregation","script","response-validation"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}