apache/iceberg · error · UnsupportedOperationException

does not implement countFor(StructLike)

Error message

 does not implement countFor(StructLike)

What it means

CountAggregate is an abstract aggregate evaluated either over StructLike rows or DataFile metadata. The StructLike overload countFor(StructLike) is a stub that throws UnsupportedOperationException; concrete subclasses must override it. Calling eval()/countFor with a row-based context on a subclass that only implemented the DataFile variant hits this.

Source

Thrown at api/src/main/java/org/apache/iceberg/expressions/CountAggregate.java:40

import org.apache.iceberg.StructLike;

public class CountAggregate<T> extends BoundAggregate<T, Long> {
  protected CountAggregate(Operation op, BoundTerm<T> term) {
    super(op, term);
  }

  @Override
  public Long eval(StructLike struct) {
    return countFor(struct);
  }

  @Override
  public Long eval(DataFile file) {
    return countFor(file);
  }

  protected Long countFor(StructLike row) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement countFor(StructLike)");
  }

  protected Long countFor(DataFile file) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " does not implement countFor(DataFile)");
  }

  @Override
  public Aggregator<Long> newAggregator() {
    return new CountAggregator<>(this);
  }

  private static class CountAggregator<T> extends NullSafeAggregator<T, Long> {
    private Long count = 0L;

    CountAggregator(BoundAggregate<T, Long> aggregate) {
      super(aggregate);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Override countFor(StructLike) in your CountAggregate subclass
  2. Use the eval/countFor(DataFile) path if the aggregate is only defined over file metadata
  3. Verify which evaluator (row-based vs file-based) is being used before evaluating

Example fix

// before
class MyCount extends CountAggregate<Void> { /* only countFor(DataFile) overridden */ }
// after
class MyCount extends CountAggregate<Void> {
  @Override
  protected Long countFor(StructLike row) { return myRowBasedCount(row); }
}
Defensive patterns

Strategy: validation

Validate before calling

if (agg.getClass().equals(CountAggregate.class)) { throw new IllegalStateException("subclass must override countFor(StructLike)"); }

Type guard

boolean supportsRowEval = !(agg instanceof CountAggregate) || overridesCountForStructLike(agg);

Try / catch

try { return agg.eval(row); } catch (UnsupportedOperationException e) { /* fall back to DataFile-based evaluation */ }

Prevention

When it happens

Trigger: Calling eval(StructLike) or countFor(StructLike) on a CountAggregate subclass (e.g. one written for DataFile metrics) that has not overridden countFor(StructLike).

Common situations: Evaluating aggregate expressions (e.g. row-count aggregates) against data rows when the aggregate was implemented for file metadata evaluation, or using a custom aggregate in a context that supplies StructLike input.

Related errors


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