apache/iceberg · error · UnsupportedOperationException
Unsupported aggregate type: %s
Error message
Unsupported aggregate type: %s
What it means
UnboundAggregate.bind() only supports COUNT, COUNT_NULL, MAX, and MIN aggregate operations. If an UnboundAggregate carries any other Operation, binding cannot produce a BoundAggregate and throws UnsupportedOperationException naming the unsupported op. This is an internal exhaustiveness guard over the aggregate enum.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java:61
* @return an {@link Expression}
* @throws ValidationException if literals do not match bound references, or if comparison on
* expression is invalid
*/
@Override
public Expression bind(Types.StructType struct, boolean caseSensitive) {
switch (op()) {
case COUNT_STAR:
return new CountStar<>(null);
case COUNT:
return new CountNonNull<>(boundTerm(struct, caseSensitive));
case COUNT_NULL:
return new CountNull<>(boundTerm(struct, caseSensitive));
case MAX:
return new MaxAggregate<>(boundTerm(struct, caseSensitive));
case MIN:
return new MinAggregate<>(boundTerm(struct, caseSensitive));
default:
throw new UnsupportedOperationException("Unsupported aggregate type: " + op());
}
}
private BoundTerm<T> boundTerm(Types.StructType struct, boolean caseSensitive) {
Preconditions.checkArgument(term() != null, "Invalid aggregate term: null");
return term().bind(struct, caseSensitive);
}
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Only create aggregates for supported ops: Expressions.count(term), countNull, max, min
- Check the operation before binding and reject unsupported aggregates with a clear message
- Upgrade Iceberg if the aggregate you need (e.g. SUM) exists in a newer version, or compute it outside Iceberg expressions
Example fix
// before Aggregate agg = Expressions.aggregate(Operation.SUM, term); // throws on bind // after Aggregate agg = Expressions.count(term); // or max/min/countNull
Defensive patterns
Strategy: validation
Validate before calling
Operation op = unbound.op();
if (op != Operation.COUNT && op != Operation.COUNT_NULL && op != Operation.MAX && op != Operation.MIN) {
throw new IllegalArgumentException("Unsupported aggregate: " + op);
} Try / catch
try { BoundAggregate<?> b = unbound.bind(struct, caseSensitive); } catch (UnsupportedOperationException e) { /* reject or compute the aggregate outside Iceberg expressions */ } Prevention
- Only build aggregates via Expressions.count/countNull/max/min
- Check Iceberg version for the supported aggregate set
- When translating engine ASTs, map only supported aggregates to Iceberg Operations
When it happens
Trigger: Constructing an UnboundAggregate with an operation other than COUNT/COUNT_NULL/MAX/MIN (e.g. SUM-style ops or a mis-mapped enum) and calling bind(struct, caseSensitive) — via Expressions.aggregate or a custom expression visitor.
Common situations: Custom expression builders mapping SQL aggregates to Iceberg Operations incorrectly; code written for newer/older Iceberg versions where the supported aggregate set differs; parsers translating engine ASTs into Iceberg expressions.
Related errors
- Found already bound predicate:
- Found already bound aggregate:
- does not implement countFor(StructLike)
- ${className} does not implement countFor(DataFile)
- AboveMax has no comparator
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/659dd7a7646f0162.
Report an issue: GitHub.