apache/iceberg · error · UnsupportedOperationException
does not implement newAggregator()
Error message
does not implement newAggregator()
What it means
newAggregator() creates a streaming Aggregator instance for incremental evaluation; the BoundAggregate base class stub always throws UnsupportedOperationException. Subclasses that do not support row/streaming aggregation trigger this error.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java:50
@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()");
}
boolean containsNan(DataFile file, int fieldId) {
Long nanCount = safeGet(file.nanValueCounts(), fieldId);
return nanCount != null && nanCount > 0;
}
@Override
public BoundReference<?> ref() {
return term().ref();
}
public Type type() {
if (op() == Operation.COUNT || op() == Operation.COUNT_STAR || op() == Operation.COUNT_NULL) {
return Types.LongType.get();
} else {
return term().type();View on GitHub (pinned to 86d9c8fc54)
Solutions
- Use only COUNT/COUNT_IF/MAX/MIN aggregates with streaming Aggregator paths
- Route file-level evaluation through AggregateEvaluator instead
- Override newAggregator() in custom BoundAggregate implementations
- Check op() before requesting an Aggregator
Example fix
// before
Aggregator<?> aggregator = agg.newAggregator(); // throws
// after
switch (agg.op()) {
case COUNT: case MAX: case MIN: aggregator = agg.newAggregator(); break;
default: /* use file-metrics evaluation instead */ break;
} Defensive patterns
Strategy: type-guard
Validate before calling
boolean streamable = Set.of(Operation.COUNT, Operation.MAX, Operation.MIN).contains(agg.op());
Type guard
boolean streamable = agg instanceof BoundCount || agg instanceof BoundMax || agg instanceof BoundMin;
Try / catch
try { aggregator = agg.newAggregator(); } catch (UnsupportedOperationException e) { /* use file-metrics path instead */ } Prevention
- Only stream aggregates known to support incremental aggregation
- Route metrics evaluation through AggregateEvaluator
- Validate aggregate ops at expression-construction time
When it happens
Trigger: Requesting an Aggregator from a BoundAggregate subclass that only supports file-metrics evaluation, e.g. streaming aggregation over rows of an unsupported aggregate type.
Common situations: Custom aggregation pipelines that assume every bound aggregate can aggregate rows incrementally; running Expression aggregation paths on aggregates designed only for metrics pruning.
Related errors
- does not implement eval(StructLike)
- does not implement eval(DataFile)
- does not implement hasValue(DataFile)
- Invalid aggregate:
- Found already bound aggregate:
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/f405d01f0fbe30d9.
Report an issue: GitHub.