redis/jedis · error · IllegalArgumentException
Aggregators must not contain null elements
Error message
Aggregators must not contain null elements
What it means
TSMRangeParams.aggregation(AggregationType[], long) also rejects arrays containing null elements with IllegalArgumentException("Aggregators must not contain null elements"). A null entry would produce an invalid AGGREGATION clause on the wire, so it is refused at parameter-construction time.
Solutions
- Build the array with exact size, e.g. via list.toArray(new AggregationType[0]), rather than a pre-sized array with unfilled slots.
- Filter nulls before calling: Arrays.stream(arr).filter(Objects::nonNull).toArray(AggregationType[]::new).
- Fix the config/parser so unknown aggregator names are rejected or mapped to valid AggregationType values, not null.
Example fix
// before AggregationType[] aggs = new AggregationType[3]; aggs[0] = AggregationType.AVG; params.aggregation(aggs, 60000); // nulls -> throws // after List<AggregationType> aggs = new ArrayList<>(); aggs.add(AggregationType.AVG); params.aggregation(aggs.toArray(new AggregationType[0]), 60000);
Defensive patterns
Strategy: validation
Validate before calling
AggregationType[] cleaned = Arrays.stream(aggs).filter(Objects::nonNull).toArray(AggregationType[]::new);
if (cleaned.length == 0) throw new IllegalArgumentException("No valid aggregators");
params.aggregation(cleaned, bucketDuration); Type guard
boolean allNonNull(AggregationType[] a) {
return Arrays.stream(a).allMatch(Objects::nonNull);
} Try / catch
try {
params.aggregation(aggs, bucketMs);
} catch (IllegalArgumentException e) {
log.error("Null aggregator in array, check config mapping: {}", e.getMessage());
throw e;
} Prevention
- Avoid pre-sized arrays; build lists and convert with toArray(new AggregationType[0]).
- Parse aggregator names with a strict enum lookup that rejects unknown values instead of yielding null.
- Add Objects::nonNull filtering as a standard pre-processing step for externally supplied arrays.
When it happens
Trigger: Passing an array such as {AggregationType.AVG, null}, typically produced by pre-sized arrays (new AggregationType[n]) that were only partially filled, or lists converted with nulls coming from config/parsers.
Common situations: Allocating new AggregationType[size] and populating fewer than size entries; deserializing aggregator lists from JSON/YAML where unknown values map to null; optional aggregation slots left unset in the array.
Related errors
- Aggregators must not contain null elements
- Aggregators must not contain null elements
- DriverInfo must not be null
- Aggregators must be non-null and non-empty
- FILTER arguments must be set.
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/b8caf8d2d08203a9.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/timeseries/TSMRangeParams.java:162
/**
* Specifies multiple aggregators to be applied in a single {@code TS.MRANGE} / {@code TS.MREVRANGE} call. Aggregators are
* sent on the wire in the given order and the response values appear in the same order in {@link TSElement#getValues()}.
* Single-element arrays are accepted and behave like {@link #aggregation(AggregationType, long)}.
*
* @param aggregators ordered, non-empty list of aggregators
* @param bucketDuration aggregation bucket duration in milliseconds
* @return this
* @throws IllegalArgumentException if {@code aggregators} is empty
*/
public TSMRangeParams aggregation(AggregationType[] aggregators, long bucketDuration) {
if (aggregators != null) {
if (aggregators.length == 0) {
throw new IllegalArgumentException("Aggregators must be non-null and non-empty");
}
for (AggregationType a : aggregators) {
if (a == null) {
throw new IllegalArgumentException("Aggregators must not contain null elements");
}
}
this.aggregators = aggregators;
this.bucketDuration = bucketDuration;
} else {
this.aggregators = null;
this.bucketDuration = 0;
}
return this;
}
/**
* This requires AGGREGATION.
*/
public TSMRangeParams bucketTimestamp(String bucketTimestamp) {
this.bucketTimestamp = encode(bucketTimestamp);
return this;
}View on GitHub (pinned to 6dac31d4c2)