{"record":{"id":"dece6502c588bb95","repo":"apache/iceberg","slug":"does-not-implement-countfor-structlike","errorCode":null,"errorMessage":" does not implement countFor(StructLike)","messagePattern":" does not implement countFor\\(StructLike\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/CountAggregate.java","lineNumber":40,"sourceCode":"import org.apache.iceberg.StructLike;\n\npublic class CountAggregate<T> extends BoundAggregate<T, Long> {\n  protected CountAggregate(Operation op, BoundTerm<T> term) {\n    super(op, term);\n  }\n\n  @Override\n  public Long eval(StructLike struct) {\n    return countFor(struct);\n  }\n\n  @Override\n  public Long eval(DataFile file) {\n    return countFor(file);\n  }\n\n  protected Long countFor(StructLike row) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement countFor(StructLike)\");\n  }\n\n  protected Long countFor(DataFile file) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement countFor(DataFile)\");\n  }\n\n  @Override\n  public Aggregator<Long> newAggregator() {\n    return new CountAggregator<>(this);\n  }\n\n  private static class CountAggregator<T> extends NullSafeAggregator<T, Long> {\n    private Long count = 0L;\n\n    CountAggregator(BoundAggregate<T, Long> aggregate) {\n      super(aggregate);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/CountAggregate.java#L22-L58","documentation":"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.","triggerScenarios":"Calling eval(StructLike) or countFor(StructLike) on a CountAggregate subclass (e.g. one written for DataFile metrics) that has not overridden countFor(StructLike).","commonSituations":"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.","solutions":["Override countFor(StructLike) in your CountAggregate subclass","Use the eval/countFor(DataFile) path if the aggregate is only defined over file metadata","Verify which evaluator (row-based vs file-based) is being used before evaluating"],"exampleFix":"// before\nclass MyCount extends CountAggregate<Void> { /* only countFor(DataFile) overridden */ }\n// after\nclass MyCount extends CountAggregate<Void> {\n  @Override\n  protected Long countFor(StructLike row) { return myRowBasedCount(row); }\n}","handlingStrategy":"validation","validationCode":"if (agg.getClass().equals(CountAggregate.class)) { throw new IllegalStateException(\"subclass must override countFor(StructLike)\"); }","typeGuard":"boolean supportsRowEval = !(agg instanceof CountAggregate) || overridesCountForStructLike(agg);","tryCatchPattern":"try { return agg.eval(row); } catch (UnsupportedOperationException e) { /* fall back to DataFile-based evaluation */ }","preventionTips":["Override countFor(StructLike) in every CountAggregate subclass","Match aggregate implementation to the evaluation context (rows vs DataFile)","Document which evaluation modes each custom aggregate supports"],"tags":["expressions","aggregate","unsupported-operation"],"backgroundTag":"method-not-implemented","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"}