apache/iceberg · error · UnsupportedOperationException

${className} does not implement countFor(DataFile)

Error message

${className} does not implement countFor(DataFile)

What it means

The DataFile overload of CountAggregate.countFor is likewise a stub throwing UnsupportedOperationException. Concrete subclasses must override countFor(DataFile) to compute counts from file metadata. Evaluating the aggregate with a DataFile evaluator on a subclass lacking that override throws this.

Source

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

  }

  @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);
    }

    @Override
    protected void update(Long value) {
      count += value;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Override countFor(DataFile) in the CountAggregate subclass
  2. Restrict evaluation to row-based paths if only the StructLike variant exists
  3. Check the aggregate's supported evaluation mode before choosing the evaluator

Example fix

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

Strategy: validation

Validate before calling

// ensure the subclass implements the DataFile path before scan-planning evaluation
if (!implementsDataFileCount(agg)) { throw new IllegalStateException("subclass must override countFor(DataFile)"); }

Type guard

boolean supportsFileEval = !(agg instanceof CountAggregate) || overridesCountForDataFile(agg);

Try / catch

try { return agg.eval(dataFile); } catch (UnsupportedOperationException e) { /* fall back to row-based evaluation or skip metric pushdown */ }

Prevention

When it happens

Trigger: Calling eval(DataFile) or countFor(DataFile) on a CountAggregate subclass that only implemented countFor(StructLike).

Common situations: Running aggregate expressions during scan planning (which evaluates against DataFile objects) with an aggregate subclass implemented only for row-level evaluation.

Related errors


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