{"record":{"id":"432eeaa1afbef427","repo":"redis/node-redis","slug":"all-replies-must-be-numbers-for-max-aggregation","errorCode":null,"errorMessage":"All replies must be numbers for max aggregation","messagePattern":"All replies must be numbers for max aggregation","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/cluster/request-response-policies/generic-aggregators.ts","lineNumber":140,"sourceCode":"    throw new Error('All replies must be numbers for min aggregation');\n  }\n  return Math.min(...replies) as T;\n};\n\n/**\n * Aggregates shard replies by taking the maximum value.\n * @remarks\n * Mirrors {@link aggregateMin}: scalar replies fold to a single maximum, array\n * replies fold element-wise (AGG_MAX semantics). Input structure is validated\n * at runtime; the generic `T` is for call-site ergonomy only.\n */\nexport const aggregateMax = <T>(replies: Array<unknown>): T => {\n  if (replies.length === 0) return 0 as T;\n  if (Array.isArray(replies[0])) {\n    return aggregateElementwise(replies, Math.max, 'max') as T;\n  }\n  if (!replies.every((reply): reply is number => typeof reply === 'number')) {\n    throw new Error('All replies must be numbers for max aggregation');\n  }\n  return Math.max(...replies) as T;\n};\n\n/**\n * Aggregates multiple numbers by finding the sum of all values.\n * @remarks\n * This implementation is specifically designed for Array<number> type only,\n * despite the generic type parameter. The generic type parameter T is provided\n * for usage ergonomy, but the actual input structure will be validated at runtime.\n */\nexport const aggregateSum = <T>(replies: Array<unknown>): T => {\n  if (replies.length === 0) return 0 as T;\n  if (!replies.every((reply): reply is number => typeof reply === 'number')) {\n    throw new Error('All replies must be numbers for sum aggregation');\n  }\n  return replies.reduce((acc, reply) => acc + reply, 0) as T;\n};","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/cluster/request-response-policies/generic-aggregators.ts#L122-L158","documentation":"Thrown by aggregateMax (scalar path) when at least one shard's reply is not a number. Used by CLIENT DISCARD / CLIENT DISCARDALL (all_shards + agg_max), where each shard returns a scalar integer. Mirrors aggregateMin's validation: if the first reply is not an array, all replies must be scalar numbers.","triggerScenarios":"CLIENT DISCARD/DISCARDALL under cluster mode where one shard returns a non-number; a shard erroring or returning an unexpected reply type; RESP decode producing a non-number.","commonSituations":"Mixed Redis versions; degraded shard returning an unexpected reply; type-mapping interference.","solutions":["Ensure all cluster nodes run the same Redis version","Check shard health and connectivity","Verify typeMapping configuration does not interfere with NUMBER decoding"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isMaxAggError(err: unknown): boolean {\n  return err instanceof Error && err.message.includes('max aggregation');\n}","tryCatchPattern":"try {\n  // e.g. CLIENT DISCARD under cluster mode\n  await cluster.sendCommand(true, 'CLIENT', 'DISCARD');\n} catch (err) {\n  if (err instanceof Error && err.message.includes('max aggregation')) {\n    // shard returned non-number — check version consistency\n  } else {\n    throw err;\n  }\n}","preventionTips":["Ensure all cluster nodes run the same Redis version","Monitor shard health for unexpected reply shapes","Verify typeMapping does not affect NUMBER decoding in aggregation paths"],"tags":["cluster","aggregation","client","response-validation"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}