{"record":{"id":"5c5dff0917fd4ae4","repo":"redis/jedis","slug":"aggregators-must-be-non-null-and-non-empty-5c5dff","errorCode":null,"errorMessage":"Aggregators must be non-null and non-empty","messagePattern":"Aggregators must be non-null and non-empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/timeseries/TSNRangeParams.java","lineNumber":135,"sourceCode":"  }\n\n  /**\n   * Applies exactly one aggregator per key, in key order. The number of aggregators must equal the\n   * number of keys sent to the command (the server rejects a mismatch). On the wire each aggregator\n   * 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","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/timeseries/TSNRangeParams.java#L117-L153","documentation":"TSNRangeParams.aggregation(AggregationType[] aggregators, long bucketDuration) supports per-key aggregations for TS.NRANGE/TS.MRANGE-style node queries. When a non-null array is supplied it must be non-empty; an empty array throws IllegalArgumentException(\"Aggregators must be non-null and non-empty\") because the AGGREGATION clause requires at least one aggregator.","triggerScenarios":"Calling aggregation(new AggregationType[0], bucketDuration) or converting an empty aggregator collection to an array and passing it, e.g. aggregation(aggSet.toArray(new AggregationType[0]), 60_000) with an empty set.","commonSituations":"Dashboard/config-driven construction where the per-node aggregation list defaults to empty; refactors from the single-aggregator overload to the array overload while keeping an empty default; user deselected all aggregations in a UI.","solutions":["Pass at least one AggregationType per key, e.g. aggregation(new AggregationType[]{AggregationType.SUM}, 60000).","Skip the aggregation call entirely when the list is empty rather than passing an empty array.","Validate aggregator selection upstream (config/UI) to guarantee at least one entry when aggregation is desired."],"exampleFix":"// before\nnode.aggregation(aggs.toArray(new AggregationType[0]), 60000); // throws when empty\n// after\nif (!aggs.isEmpty()) {\n  node.aggregation(aggs.toArray(new AggregationType[0]), 60000);\n}","handlingStrategy":"validation","validationCode":"if (aggs != null && aggs.length == 0) {\n  throw new IllegalArgumentException(\"Provide at least one AggregationType for TSNRangeParams\");\n}\nnode.aggregation(aggs, bucketDuration);","typeGuard":"boolean hasAggregators(AggregationType[] a) {\n  return a == null || a.length > 0; // null means no aggregation and is allowed\n}","tryCatchPattern":"try {\n  node.aggregation(aggs, bucketMs);\n} catch (IllegalArgumentException e) {\n  log.warn(\"Skipping aggregation (empty aggregator array): {}\", e.getMessage());\n}","preventionTips":["Call aggregation only with a non-empty aggregator array; null is the correct way to signal 'no aggregation'.","Check collection emptiness before converting to arrays.","Ensure UI/config defaults do not produce empty aggregator selections."],"tags":["java","timeseries","validation"],"backgroundTag":"empty-required-field","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"}