{"record":{"id":"dc3ba91b3bc0dd3a","repo":"apache/iceberg","slug":"does-not-implement-hasvalue-datafile","errorCode":null,"errorMessage":" does not implement hasValue(DataFile)","messagePattern":" does not implement hasValue\\(DataFile\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java","lineNumber":45,"sourceCode":"public class BoundAggregate<T, C> extends Aggregate<BoundTerm<T>> implements Bound<C> {\n\n  protected BoundAggregate(Operation op, BoundTerm<T> term) {\n    super(op, term);\n  }\n\n  @Override\n  public C eval(StructLike struct) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement eval(StructLike)\");\n  }\n\n  C eval(DataFile file) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement eval(DataFile)\");\n  }\n\n  boolean hasValue(DataFile file) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement hasValue(DataFile)\");\n  }\n\n  Aggregator<C> newAggregator() {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" does not implement newAggregator()\");\n  }\n\n  boolean containsNan(DataFile file, int fieldId) {\n    Long nanCount = safeGet(file.nanValueCounts(), fieldId);\n    return nanCount != null && nanCount > 0;\n  }\n\n  @Override\n  public BoundReference<?> ref() {\n    return term().ref();\n  }\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java#L27-L63","documentation":"hasValue(DataFile) indicates whether a data file's metrics contain a value the aggregate can use; the base BoundAggregate stub always throws. Subclasses not supporting file-level metrics evaluation trigger this UnsupportedOperationException.","triggerScenarios":"Calling hasValue(DataFile) on a BoundAggregate subclass lacking file-metrics support, typically during file pruning with aggregate pushdown.","commonSituations":"Custom pruning implementations probing metrics for aggregate types that do not support them; API evolution where new aggregates lag behind file-level support.","solutions":["Guard with try-catch or check op() type before calling hasValue","Use AggregateEvaluator's supported aggregates for file pruning","Override hasValue(DataFile) in custom subclasses","Default to assuming a value exists (no pruning) when unsupported"],"exampleFix":"// before\nboolean has = agg.hasValue(dataFile); // throws\n// after\nboolean has = agg.op() == Operation.COUNT || agg.evalHasValue(dataFile); // route via supported path","handlingStrategy":"try-catch","validationCode":"boolean supported = Set.of(Operation.COUNT, Operation.MAX, Operation.MIN).contains(agg.op());","typeGuard":null,"tryCatchPattern":"try { has = agg.hasValue(dataFile); } catch (UnsupportedOperationException e) { has = true; /* assume value present, skip pruning */ }","preventionTips":["Check op() support before probing hasValue","Treat unsupported aggregates as non-prunable","Wrap file-pruning loops with safe fallbacks"],"tags":["expressions","aggregates","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"}