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

  1. Only create aggregates for supported ops: Expressions.count(term), countNull, max, min
  2. Check the operation before binding and reject unsupported aggregates with a clear message
  3. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/659dd7a7646f0162. Report an issue: GitHub.