redis/jedis · error · IllegalArgumentException

Aggregators must be non-null and non-empty

Error message

Aggregators must be non-null and non-empty

What it means

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.

Solutions

  1. Pass at least one AggregationType per key, e.g. aggregation(new AggregationType[]{AggregationType.SUM}, 60000).
  2. Skip the aggregation call entirely when the list is empty rather than passing an empty array.
  3. Validate aggregator selection upstream (config/UI) to guarantee at least one entry when aggregation is desired.

Example fix

// before
node.aggregation(aggs.toArray(new AggregationType[0]), 60000); // throws when empty
// after
if (!aggs.isEmpty()) {
  node.aggregation(aggs.toArray(new AggregationType[0]), 60000);
}
Defensive patterns

Strategy: validation

Validate before calling

if (aggs != null && aggs.length == 0) {
  throw new IllegalArgumentException("Provide at least one AggregationType for TSNRangeParams");
}
node.aggregation(aggs, bucketDuration);

Type guard

boolean hasAggregators(AggregationType[] a) {
  return a == null || a.length > 0; // null means no aggregation and is allowed
}

Try / catch

try {
  node.aggregation(aggs, bucketMs);
} catch (IllegalArgumentException e) {
  log.warn("Skipping aggregation (empty aggregator array): {}", e.getMessage());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/5c5dff0917fd4ae4. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/timeseries/TSNRangeParams.java:135

  }

  /**
   * Applies exactly one aggregator per key, in key order. The number of aggregators must equal the
   * number of keys sent to the command (the server rejects a mismatch). On the wire each aggregator
   * is emitted as its own {@code AGGREGATION} token.
   * @param aggregators ordered, non-empty list holding one aggregator per key
   * @param bucketDuration aggregation bucket duration in milliseconds
   * @return this
   * @throws IllegalArgumentException if {@code aggregators} is empty or contains a null element
   */
  public TSNRangeParams aggregation(AggregationType[] aggregators, long bucketDuration) {
    if (aggregators == null) {
      this.aggregators = null;
      this.bucketDuration = 0;
      return this;
    }
    if (aggregators.length == 0) {
      throw new IllegalArgumentException("Aggregators must be non-null and non-empty");
    }
    AggregationType[][] perKey = new AggregationType[aggregators.length][];
    for (int i = 0; i < aggregators.length; i++) {
      if (aggregators[i] == null) {
        throw new IllegalArgumentException("Aggregators must not contain null elements");
      }
      perKey[i] = new AggregationType[] { aggregators[i] };
    }
    this.aggregators = perKey;
    this.bucketDuration = bucketDuration;
    return this;
  }

  /**
   * Applies one or more aggregators per key, in key order. The outer array length must equal the
   * number of keys sent to the command (the server rejects a mismatch); each inner array holds the
   * aggregators for that key and is emitted as a single comma-joined {@code AGGREGATION} token
   * (e.g. {@code AVG,MAX}). The response returns one value column per aggregator, flattened in key

View on GitHub (pinned to 6dac31d4c2)