{"record":{"id":"659dd7a7646f0162","repo":"apache/iceberg","slug":"unsupported-aggregate-type-s","errorCode":null,"errorMessage":"Unsupported aggregate type: %s","messagePattern":"Unsupported aggregate type: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java","lineNumber":61,"sourceCode":"   * @return an {@link Expression}\n   * @throws ValidationException if literals do not match bound references, or if comparison on\n   *     expression is invalid\n   */\n  @Override\n  public Expression bind(Types.StructType struct, boolean caseSensitive) {\n    switch (op()) {\n      case COUNT_STAR:\n        return new CountStar<>(null);\n      case COUNT:\n        return new CountNonNull<>(boundTerm(struct, caseSensitive));\n      case COUNT_NULL:\n        return new CountNull<>(boundTerm(struct, caseSensitive));\n      case MAX:\n        return new MaxAggregate<>(boundTerm(struct, caseSensitive));\n      case MIN:\n        return new MinAggregate<>(boundTerm(struct, caseSensitive));\n      default:\n        throw new UnsupportedOperationException(\"Unsupported aggregate type: \" + op());\n    }\n  }\n\n  private BoundTerm<T> boundTerm(Types.StructType struct, boolean caseSensitive) {\n    Preconditions.checkArgument(term() != null, \"Invalid aggregate term: null\");\n    return term().bind(struct, caseSensitive);\n  }\n}\n","sourceCodeStart":43,"sourceCodeEnd":70,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java#L43-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nAggregate agg = Expressions.aggregate(Operation.SUM, term); // throws on bind\n// after\nAggregate agg = Expressions.count(term); // or max/min/countNull","handlingStrategy":"validation","validationCode":"Operation op = unbound.op();\nif (op != Operation.COUNT && op != Operation.COUNT_NULL && op != Operation.MAX && op != Operation.MIN) {\n  throw new IllegalArgumentException(\"Unsupported aggregate: \" + op);\n}","typeGuard":null,"tryCatchPattern":"try { BoundAggregate<?> b = unbound.bind(struct, caseSensitive); } catch (UnsupportedOperationException e) { /* reject or compute the aggregate outside Iceberg expressions */ }","preventionTips":["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"],"tags":["expressions","aggregate","binding","unsupported"],"backgroundTag":"unsupported-enum-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}