{"record":{"id":"0564bed80220853e","repo":"apache/iceberg","slug":"classname-does-not-implement-isnan","errorCode":null,"errorMessage":"${className} does not implement isNaN","messagePattern":"(.+?) does not implement isNaN","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java","lineNumber":78,"sourceCode":"      throw new UnsupportedOperationException(\"Cannot visit aggregate expression\");\n    }\n\n    public <T> R aggregate(UnboundAggregate<T> agg) {\n      throw new UnsupportedOperationException(\"Cannot visit aggregate expression\");\n    }\n  }\n\n  public abstract static class BoundExpressionVisitor<R> extends ExpressionVisitor<R> {\n    public <T> R isNull(BoundReference<T> ref) {\n      return null;\n    }\n\n    public <T> R notNull(BoundReference<T> ref) {\n      return null;\n    }\n\n    public <T> R isNaN(BoundReference<T> ref) {\n      throw new UnsupportedOperationException(\n          this.getClass().getName() + \" does not implement isNaN\");\n    }\n\n    public <T> R notNaN(BoundReference<T> ref) {\n      throw new UnsupportedOperationException(\n          this.getClass().getName() + \" does not implement notNaN\");\n    }\n\n    public <T> R lt(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R ltEq(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R gt(BoundReference<T> ref, Literal<T> lit) {\n      return null;","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java#L60-L96","documentation":"BoundExpressionVisitor.isNaN has no default no-op; the base class throws naming the visitor class that failed to implement it, forcing subclasses to consciously handle NaN checks (important for float/double columns).","triggerScenarios":"Evaluating or visiting an isNaN(floatCol) predicate with a BoundExpressionVisitor subclass that overrides other predicate methods but not isNaN — typically during Bind→visit of row filters containing NaN checks.","commonSituations":"Custom visitors written before isNaN was added to the API (older subclass compiled against/behaving like the older base); filter visitors that handled isNull/notNull but forgot NaN cases on floating-point columns.","solutions":["Override isNaN(BoundReference) (and notNaN) in your visitor subclass","Extend a higher-level visitor (e.g. ExpressionVisitors.CustomOrderExpressionVisitor or evaluator visitors) that already implements NaN handling","Recompile/refresh subclasses after upgrading Iceberg so newly added required methods are implemented"],"exampleFix":"// before\nclass MyVisitor<R> extends ExpressionVisitors.BoundExpressionVisitor<R> {\n  @Override public <T> R isNull(BoundReference<T> ref) { return handleNull(ref); }\n}\n// after\nclass MyVisitor<R> extends ExpressionVisitors.BoundExpressionVisitor<R> {\n  @Override public <T> R isNull(BoundReference<T> ref) { return handleNull(ref); }\n  @Override public <T> R isNaN(BoundReference<T> ref) { return handleNaN(ref); }\n  @Override public <T> R notNaN(BoundReference<T> ref) { return handleNotNaN(ref); }\n}","handlingStrategy":"validation","validationCode":"Set<java.lang.reflect.Method> m = Set.of(visitor.getClass().getMethods());\nif (!m.contains(visitor.getClass().getMethod(\"isNaN\", BoundReference.class))) {\n  throw new IllegalArgumentException(\"visitor must override isNaN\");\n}","typeGuard":null,"tryCatchPattern":"try { return visitPredicate(pred, visitor); }\ncatch (UnsupportedOperationException e) { throw new IllegalStateException(\"Visitor \" + visitor.getClass() + \" must implement isNaN/notNaN\", e); }","preventionTips":["Always override isNaN and notNaN when extending BoundExpressionVisitor","Handle NaN for floating-point columns explicitly","Recompile subclasses against new Iceberg API versions"],"tags":["expressions","visitor-pattern","nan"],"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-23T08:17:48.524Z"}