apache/iceberg · error · UnsupportedOperationException
Cannot visit aggregate expression
Error message
Cannot visit aggregate expression
What it means
ExpressionVisitor's default aggregate(BoundAggregate) implementation throws because plain expression visitors are not designed to handle aggregates (count, sum, max). Subclasses must override the aggregate methods to support them.
Solutions
- Use a visitor class that overrides aggregate(BoundAggregate), e.g. extend ExpressionVisitors.AggregateVisitor
- Override aggregate(BoundAggregate) (and aggregate(UnboundAggregate)) in your visitor subclass
- Route aggregate expressions to aggregate-specific APIs instead of generic ExpressionVisitors.visit
Example fix
// before
ExpressionVisitors.visit(boundAggregate, new ExpressionVisitors.ExpressionVisitor<Object>() {});
// after
ExpressionVisitors.visit(boundAggregate, new ExpressionVisitors.AggregateVisitor<Object>() {
@Override
public <T, C> Object aggregate(BoundAggregate<T, C> agg) { return handleAgg(agg); }
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (expr instanceof BoundAggregate && !(visitor instanceof ExpressionVisitors.AggregateVisitor)) {
throw new IllegalArgumentException("use an AggregateVisitor for aggregate expressions");
} Type guard
boolean canVisitAggregates(ExpressionVisitor<?> v) {
return v instanceof ExpressionVisitors.AggregateVisitor;
} Try / catch
try { return ExpressionVisitors.visit(boundAgg, visitor); }
catch (UnsupportedOperationException e) { throw new IllegalStateException("Visitor does not support aggregates; use AggregateVisitor", e); } Prevention
- Never reuse filter visitors on aggregate expressions
- Override both aggregate(BoundAggregate) and aggregate(UnboundAggregate)
- Check expression kind before dispatching to generic visit
When it happens
Trigger: Visiting an expression tree containing a BoundAggregate with a visitor class that does not override aggregate(BoundAggregate), e.g. via ExpressionVisitors.visit(agg, visitor).
Common situations: Using an ExpressionVisitor built for filters (Evaluator-style visitors) on aggregate expressions; metrics/aggregation code reusing a filter visitor; library code visiting rewrite plans containing aggregates.
Related errors
- does not implement isNaN
- does not implement eval(DataFile)
- does not implement eval(StructLike)
- does not implement hasValue(DataFile)
- does not implement newAggregator()
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/f870d21268bdcc3f.
Report an issue: GitHub.
Appendix: source
Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java:60
public R and(R leftResult, R rightResult) {
return null;
}
public R or(R leftResult, R rightResult) {
return null;
}
public <T> R predicate(BoundPredicate<T> pred) {
return null;
}
public <T> R predicate(UnboundPredicate<T> pred) {
return null;
}
public <T, C> R aggregate(BoundAggregate<T, C> agg) {
throw new UnsupportedOperationException("Cannot visit aggregate expression");
}
public <T> R aggregate(UnboundAggregate<T> agg) {
throw new UnsupportedOperationException("Cannot visit aggregate expression");
}
}
public abstract static class BoundExpressionVisitor<R> extends ExpressionVisitor<R> {
public <T> R isNull(BoundReference<T> ref) {
return null;
}
public <T> R notNull(BoundReference<T> ref) {
return null;
}
public <T> R isNaN(BoundReference<T> ref) {
throw new UnsupportedOperationException(View on GitHub (pinned to 86d9c8fc54)