{"record":{"id":"de0e97245cf8de40","repo":"redis/jedis","slug":"aggregators-must-not-contain-null-elements-de0e97","errorCode":null,"errorMessage":"Aggregators must not contain null elements","messagePattern":"Aggregators must not contain null elements","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/timeseries/TSNRangeParams.java","lineNumber":140,"sourceCode":"   * is emitted as its own {@code AGGREGATION} token.\n   * @param aggregators ordered, non-empty list holding one aggregator per key\n   * @param bucketDuration aggregation bucket duration in milliseconds\n   * @return this\n   * @throws IllegalArgumentException if {@code aggregators} is empty or contains a null element\n   */\n  public TSNRangeParams aggregation(AggregationType[] aggregators, long bucketDuration) {\n    if (aggregators == null) {\n      this.aggregators = null;\n      this.bucketDuration = 0;\n      return this;\n    }\n    if (aggregators.length == 0) {\n      throw new IllegalArgumentException(\"Aggregators must be non-null and non-empty\");\n    }\n    AggregationType[][] perKey = new AggregationType[aggregators.length][];\n    for (int i = 0; i < aggregators.length; i++) {\n      if (aggregators[i] == null) {\n        throw new IllegalArgumentException(\"Aggregators must not contain null elements\");\n      }\n      perKey[i] = new AggregationType[] { aggregators[i] };\n    }\n    this.aggregators = perKey;\n    this.bucketDuration = bucketDuration;\n    return this;\n  }\n\n  /**\n   * Applies one or more aggregators per key, in key order. The outer array length must equal the\n   * number of keys sent to the command (the server rejects a mismatch); each inner array holds the\n   * aggregators for that key and is emitted as a single comma-joined {@code AGGREGATION} token\n   * (e.g. {@code AVG,MAX}). The response returns one value column per aggregator, flattened in key\n   * then aggregator order.\n   * @param aggregators ordered, non-empty per-key lists of aggregators\n   * @param bucketDuration aggregation bucket duration in milliseconds\n   * @return this\n   * @throws IllegalArgumentException if {@code aggregators} (or any inner array) is empty or","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/timeseries/TSNRangeParams.java#L122-L158","documentation":"TSNRangeParams.aggregation(AggregationType[], long) rejects null elements inside the aggregators array with IllegalArgumentException(\"Aggregators must not contain null elements\"), wrapping each entry into a per-key single-element array; a null entry would generate an invalid command, so it is rejected during parameter construction.","triggerScenarios":"Passing an array containing nulls, typically from pre-sized partially filled arrays (new AggregationType[n]) or from lists deserialized from config where unknown aggregator names became null.","commonSituations":"Building per-key aggregator arrays with placeholder null slots; YAML/JSON config mapping unrecognized aggregation names to null; merging multiple sources of aggregator settings where some are absent.","solutions":["Filter nulls before the call: Arrays.stream(arr).filter(Objects::nonNull).toArray(AggregationType[]::new).","Use exact-size collections converted with toArray(new AggregationType[0]) instead of pre-sized arrays.","Make the config parser reject unknown aggregator names instead of silently mapping them to null."],"exampleFix":"// before\nAggregationType[] a = new AggregationType[2];\na[0] = AggregationType.MIN;\nnode.aggregation(a, 60000); // null element -> throws\n// after\nList<AggregationType> a = new ArrayList<>();\na.add(AggregationType.MIN);\nnode.aggregation(a.toArray(new AggregationType[0]), 60000);","handlingStrategy":"validation","validationCode":"AggregationType[] cleaned = Arrays.stream(aggs).filter(Objects::nonNull).toArray(AggregationType[]::new);\nnode.aggregation(cleaned.length > 0 ? cleaned : null, bucketDuration);","typeGuard":"boolean noNullElements(AggregationType[] a) {\n  return a == null || Arrays.stream(a).noneMatch(Objects::isNull);\n}","tryCatchPattern":"try {\n  node.aggregation(aggs, bucketMs);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"null elements\")) {\n    throw new IllegalStateException(\"Unmapped aggregator name in config produced null; fix the enum parsing\", e);\n  }\n  throw e;\n}","preventionTips":["Sanitize external arrays with Objects::nonNull filtering before passing to aggregation.","Avoid pre-sized arrays with unfilled slots; use growable lists.","Make config parsing of AggregationType fail loudly on unknown names rather than returning null."],"tags":["java","timeseries","validation","null-check"],"backgroundTag":"null-argument","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}