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

  1. Use a visitor class that overrides aggregate(BoundAggregate), e.g. extend ExpressionVisitors.AggregateVisitor
  2. Override aggregate(BoundAggregate) (and aggregate(UnboundAggregate)) in your visitor subclass
  3. 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

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


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)