redis/jedis · error · IllegalStateException
REDUCE COLLECT cannot mix FIELDS * with explicit field names
Error message
REDUCE COLLECT cannot mix FIELDS * with explicit field names
What it means
CollectReducer's REDUCE COLLECT lets you collect either an explicit list of fields or all fields (FIELDS *), but not both. Calling fields(String...) after fieldsAll() was already set throws this IllegalStateException because the two configurations are mutually exclusive in the generated aggregate query.
Solutions
- Choose one mode: call fields(...) with explicit names OR fieldsAll(), never both on the same reducer
- If a default of all-fields exists, clear/reset the reducer (build a new CollectReducer) before adding explicit fields
- Refactor dynamic builders so the mode decision happens once before adding field names
Example fix
// before
CollectReducer r = new CollectReducer().fieldsAll().fields("@title"); // IllegalStateException
// after
CollectReducer r = new CollectReducer().fields("@title", "@body");
// or
CollectReducer r = new CollectReducer().fieldsAll(); Defensive patterns
Strategy: validation
Validate before calling
if (useAllFields && explicitFields.length > 0) {
throw new IllegalStateException("Choose either fieldsAll() or fields(...), not both");
} Type guard
null
Try / catch
try {
reducer.fields("@title");
} catch (IllegalStateException e) {
// fieldsAll() already set — rebuild the reducer in a single mode
} Prevention
- Decide the fields mode before building the reducer; use one branch, never both
- Construct a fresh CollectReducer when requirements change instead of mutating a shared one
- Keep builder chains linear and single-purpose
- Add unit tests for dynamic reducer construction covering both modes
When it happens
Trigger: Calling reducer.fieldsAll() followed by reducer.fields("@a","@b") on the same CollectReducer instance (builder-chain or fluent reuse).
Common situations: Building reducers dynamically and appending field names after defaulting to all-fields; copy-pasting reducer configuration where fieldsAll() appears earlier in the chain; reusing a shared reducer builder for multiple queries.
Related errors
- REDUCE COLLECT requires either fields(...) or fieldsAll()…
- DIALECT=0 cannot be set.
- No connections available from connection provider
- No more aggregation results available
- Failed to fetch next aggregation batch
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/9c90897f562b2cd2.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/search/aggr/CollectReducer.java:76
private boolean allFields = false;
private final List<String> fields = new ArrayList<>();
private final List<SortedField> sortFields = new ArrayList<>();
private Integer limitOffset;
private Integer limitCount;
CollectReducer() {
super("COLLECT");
}
/**
* Project the named fields for every document in the group. Use {@code @__key}, {@code @__score}
* or document field names (e.g. {@code @title}).
* <p>
* Mutually exclusive with {@link #fieldsAll()}.
*/
public CollectReducer fields(String... fields) {
if (this.allFields) {
throw new IllegalStateException(
"REDUCE COLLECT cannot mix FIELDS * with explicit field names");
}
Collections.addAll(this.fields, fields);
return this;
}
/**
* Project every field available in the current input row ({@code FIELDS *}).
* <p>
* Per the COLLECT specification, {@code *} does not trigger an implicit load — fields must
* already be in the pipeline (typically via {@code LOAD *} or because they are grouping keys /
* reducer aliases).
* <p>
* Mutually exclusive with {@link #fields(String...)}.
*/
public CollectReducer fieldsAll() {
if (!this.fields.isEmpty()) {
throw new IllegalStateException(View on GitHub (pinned to 6dac31d4c2)