apache/iceberg · error · UnsupportedOperationException

does not implement eval(StructLike)

Error message

 does not implement eval(StructLike)

What it means

The abstract BoundAggregate.eval(StructLike) has no generic implementation because per-row evaluation is specific to each concrete aggregate type. Subclasses that do not support row-level evaluation inherit this stub, which throws UnsupportedOperationException with the concrete class name.

Source

Thrown at api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java:35

 * under the License.
 */
package org.apache.iceberg.expressions;

import java.util.Map;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.StructLike;
import org.apache.iceberg.types.Type;
import org.apache.iceberg.types.Types;

public class BoundAggregate<T, C> extends Aggregate<BoundTerm<T>> implements Bound<C> {

  protected BoundAggregate(Operation op, BoundTerm<T> term) {
    super(op, term);
  }

  @Override
  public C eval(StructLike struct) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement eval(StructLike)");
  }

  C eval(DataFile file) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement eval(DataFile)");
  }

  boolean hasValue(DataFile file) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement hasValue(DataFile)");
  }

  Aggregator<C> newAggregator() {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement newAggregator()");
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Evaluate aggregates at the data-file level via eval(DataFile) instead of per-row
  2. Only use aggregate expressions with AggregateEvaluator / metrics evaluation APIs
  3. If writing a custom BoundAggregate subclass, override eval(StructLike)
  4. Check the aggregate operation type before attempting row evaluation

Example fix

// before
Object value = boundAggregate.eval(rowStruct); // throws
// after
Object value = boundAggregate.eval(dataFile); // metrics-level evaluation
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(agg.op() == Operation.COUNT || agg.op() == Operation.MAX || agg.op() == Operation.MIN)) { /* not row-evaluable */ }

Type guard

boolean rowEvaluable = agg instanceof BoundCount || agg instanceof BoundMax || agg instanceof BoundMin;

Try / catch

try { v = agg.eval(struct); } catch (UnsupportedOperationException e) { /* fall back to file-level eval(DataFile) */ }

Prevention

When it happens

Trigger: Calling eval(StructLike) on a BoundCount, BoundMax, or BoundMin subclass instance that only implements eval(DataFile), e.g. evaluating a metrics aggregate against individual rows.

Common situations: Custom expression evaluation code that assumes every bound expression supports row evaluation; using aggregate expressions in row-filter pipelines where they were meant for file-level metric pruning.

Related errors


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