redis/jedis · error · UnsupportedAggregationException
requires Boolean, Long, ArrayList , or ArrayList , but got
Error message
${operationName} requires Boolean, Long, ArrayList<Boolean>, or ArrayList<Long>, but got: ${input.getClass().getName()} What it means
LogicalBinaryAggregator merges Boolean/Long replies from a two-shard logical broadcast (e.g. EXISTS-style checks with ALL-SUCC / ANY-SUCC policies). The first non-null input must be Boolean, Long, or an ArrayList; anything else throws UnsupportedAggregationException with the actual type. It enforces that logical operations only aggregate boolean-like results.
Solutions
- Ensure the command's Builder converts replies to Boolean or Long (BuilderFactory.BOOLEAN / LONG) before aggregation.
- Use a non-logical response policy if the command genuinely returns other types.
- For multi-value results, parse into ArrayList<Boolean>/ArrayList<Long> so the aggregator accepts them.
Example fix
// before new CommandObject<>(args, BuilderFactory.STRING) // String fed to logical aggregator // after new CommandObject<>(args, BuilderFactory.BOOLEAN) // Boolean accepted by logical aggregator
Defensive patterns
Strategy: type-guard
Validate before calling
Object reply = jedis.sendCommand(cmd);
if (!(reply instanceof Boolean || reply instanceof Long || reply instanceof ArrayList)) {
throw new IllegalStateException("logical broadcast requires Boolean/Long replies");
} Type guard
boolean isLogicalReply(Object r) {
return r instanceof Boolean || r instanceof Long || r instanceof ArrayList;
} Try / catch
try {
return logicalBroadcast();
} catch (UnsupportedAggregationException e) {
logger.error("bad reply type for logical op: {}", e.getMessage());
throw new IllegalStateException(e);
} Prevention
- Parse logical command replies with BuilderFactory.BOOLEAN or BuilderFactory.LONG
- Reserve ALL-SU/ANY-SU style policies for boolean-returning commands
- Add unit tests asserting the Builder output type before broadcasting
When it happens
Trigger: Executing a multi-shard logical command (operationName like ANY-SUCC/ALL-SUCC aggregation) whose Builder produces a reply type other than Boolean/Long/ArrayList — e.g. a String status reply or a byte[] being aggregated.
Common situations: Custom or module commands registered with a logical response policy but parsed to String/byte[]; wiring a broadcast EXISTS-like command with a generic OBJECT builder instead of BuilderFactory.BOOLEAN/LONG.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- AGG_SUM policy requires numeric type, but got
- DEFAULT policy requires List, Set, Map, JedisByteHashMap…
- requires Boolean, Long, ArrayList , or ArrayList , but got…
- AGG_MAX policy requires Comparable types or KeyValue, but…
- AGG_MIN policy requires Comparable types or KeyValue, but…
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/736143eaffa338f4.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/executors/aggregators/LogicalBinaryAggregator.java:31
private final String operationName;
protected LogicalBinaryAggregator(String operationName) {
this.operationName = operationName;
}
@Override
public void add(T input) {
if (input == null) {
return; // ignore nulls
}
if (result == null) {
// First non-null input initializes the result
if (input instanceof Boolean || input instanceof Long || input instanceof ArrayList) {
result = input;
return;
} else {
throw new UnsupportedAggregationException(operationName
+ " requires Boolean, Long, ArrayList<Boolean>, or ArrayList<Long>, but got: "
+ input.getClass().getName());
}
}
// Handle Boolean
if (result instanceof Boolean && input instanceof Boolean) {
result = (T) Boolean.valueOf(applyBooleanOp((Boolean) result, (Boolean) input));
return;
}
// Handle Long
if (result instanceof Long && input instanceof Long) {
boolean existingBool = (Long) result != 0;
boolean newBool = (Long) input != 0;
result = (T) Long.valueOf(applyBooleanOp(existingBool, newBool) ? 1L : 0L);
return;
}View on GitHub (pinned to 6dac31d4c2)