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
- 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.
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
- 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.
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
- Aggregators must be non-null and non-empty
- Aggregators must not contain null elements
- FILTER arguments must be set.
- EXCLUDEEMPTY is not allowed with GROUPBY.
- Aggregators must not contain null elements
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 keyView on GitHub (pinned to 6dac31d4c2)