redis/jedis · error · IllegalStateException
REDUCE COLLECT requires either fields(...) or fieldsAll()…
Error message
REDUCE COLLECT requires either fields(...) or fieldsAll() to be configured
What it means
When the CollectReducer serializes itself into command arguments (getOwnArgs), it requires a fields configuration: either explicit fields(...) or fieldsAll(). A REDUCE COLLECT with neither would produce a meaningless/unserverable FIELDS clause, so it throws this IllegalStateException at query build time.
Solutions
- Call fields("@field1", ...) or fieldsAll() on every CollectReducer before executing the query
- Guard dynamic builders: if the field list is empty, either use fieldsAll() or skip adding the COLLECT reducer
- Validate the aggregation builder in application code before sending (ensure each COLLECT reducer has fields set)
Example fix
// before
aggregationBuilder.reduce(new CollectReducer()); // IllegalStateException at build/send
// after
aggregationBuilder.reduce(new CollectReducer().fieldsAll());
// or
aggregationBuilder.reduce(new CollectReducer().fields("@title", "@tags")); Defensive patterns
Strategy: validation
Validate before calling
// before sending the aggregation, verify every COLLECT reducer has fields
if (!allFields && (fields == null || fields.isEmpty())) {
throw new IllegalStateException("CollectReducer needs fields(...) or fieldsAll()");
} Type guard
null
Try / catch
try {
AggregationResult r = client.ftAggregate(indexName, aggregationBuilder);
} catch (JedisException | IllegalStateException e) {
// reducer misconfiguration — fix builder before retry
} Prevention
- Never add a bare new CollectReducer(); always finish configuration in the same expression
- In dynamic builders, default empty field lists to fieldsAll() or skip the reducer
- Validate the assembled AggregationBuilder before executing
- Cover reducer construction with unit tests that assert the generated args
When it happens
Trigger: Adding a bare new CollectReducer() to an AggregationBuilder's reduce() without ever calling fields(...) or fieldsAll(), then executing the aggregation.
Common situations: Skeleton reducer left unconfigured during development; dynamic builders that skip field configuration when a list is empty; copy-pasted reducer code where the fields call was deleted.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- REDUCE COLLECT cannot mix FIELDS * with explicit field names
- No connections available from connection provider
- No more aggregation results available
- Failed to fetch next aggregation batch
- Failed to initialize aggregation cursor
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/e659587f8037c2af.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/search/aggr/CollectReducer.java:140
/** Bound the output per group to the first {@code count} entries (offset 0). */
public CollectReducer limit(int count) {
return limit(0, count);
}
/** Bound the output per group to {@code count} entries starting at {@code offset}. */
public CollectReducer limit(int offset, int count) {
if (offset < 0 || count < 0) {
throw new IllegalArgumentException("LIMIT offset and count must be non-negative");
}
this.limitOffset = offset;
this.limitCount = count;
return this;
}
@Override
protected List<Object> getOwnArgs() {
if (!allFields && fields.isEmpty()) {
throw new IllegalStateException(
"REDUCE COLLECT requires either fields(...) or fieldsAll() to be configured");
}
List<Object> args = new ArrayList<>();
args.add(SearchKeyword.FIELDS);
if (allFields) {
args.add(Protocol.BYTES_ASTERISK);
} else {
args.add(fields.size());
args.addAll(fields);
}
if (!sortFields.isEmpty()) {
args.add(SearchKeyword.SORTBY);
args.add(sortFields.size() << 1); // 2 tokens per @field/ASC|DESC pair
for (SortedField sf : sortFields) {
args.add(sf.getField());
args.add(sf.getOrder());View on GitHub (pinned to 6dac31d4c2)