{"record":{"id":"88ab5e2cf21f0fc4","repo":"apache/iceberg","slug":"notnan-cannot-be-used-with-a-non-floating-point-co","errorCode":null,"errorMessage":"NotNaN cannot be used with a non-floating-point column","messagePattern":"NotNaN cannot be used with a non-floating-point column","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java","lineNumber":154,"sourceCode":"      case NOT_NULL:\n        if (!boundTerm.producesNull()\n            && allAncestorFieldsAreRequired(struct, boundTerm.ref().fieldId())) {\n          return Expressions.alwaysTrue();\n        } else if (boundTerm.type().equals(Types.UnknownType.get())) {\n          return Expressions.alwaysFalse();\n        }\n        return new BoundUnaryPredicate<>(Operation.NOT_NULL, boundTerm);\n      case IS_NAN:\n        if (floatingType(boundTerm.type().typeId())) {\n          return new BoundUnaryPredicate<>(Operation.IS_NAN, boundTerm);\n        } else {\n          throw new ValidationException(\"IsNaN cannot be used with a non-floating-point column\");\n        }\n      case NOT_NAN:\n        if (floatingType(boundTerm.type().typeId())) {\n          return new BoundUnaryPredicate<>(Operation.NOT_NAN, boundTerm);\n        } else {\n          throw new ValidationException(\"NotNaN cannot be used with a non-floating-point column\");\n        }\n      default:\n        throw new ValidationException(\"Operation must be IS_NULL, NOT_NULL, IS_NAN, or NOT_NAN\");\n    }\n  }\n\n  private boolean allAncestorFieldsAreRequired(StructType struct, int fieldId) {\n    return TypeUtil.ancestorFields(struct.asSchema(), fieldId).stream()\n        .allMatch(Types.NestedField::isRequired);\n  }\n\n  private boolean floatingType(Type.TypeID typeID) {\n    return Type.TypeID.DOUBLE.equals(typeID) || Type.TypeID.FLOAT.equals(typeID);\n  }\n\n  private Expression bindLiteralOperation(BoundTerm<T> boundTerm) {\n    if (op() == Operation.STARTS_WITH || op() == Operation.NOT_STARTS_WITH) {\n      ValidationException.check(","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java#L136-L172","documentation":"NOT_NAN is the negation of IS_NAN and is likewise only valid on float and double columns. Binding an UnboundPredicate with Operation.NOT_NAN against a term whose bound type is not floating-point throws this ValidationException.","triggerScenarios":"Building Expressions.notNaN(\"col\") where col resolves to int/long/decimal/string/etc., then binding the expression to a Types.StructType (e.g. via table.filter or Binder.bind).","commonSituations":"Generic filter UIs or SQL translators that emit NOT NaN for any numeric column; stale filters after a column type changed from double to decimal/long.","solutions":["Emit notNaN only for float/double columns; use notNull otherwise","Validate the referenced field's typeId before constructing the predicate","Update the filter definition after column type changes"],"exampleFix":"// before\nExpression e = Expressions.notNaN(\"long_col\");\n// after\nType t = schema.findType(\"long_col\");\nExpression e = (t.typeId() == Type.TypeID.FLOAT || t.typeId() == Type.TypeID.DOUBLE)\n    ? Expressions.notNaN(\"long_col\")\n    : Expressions.notNull(\"long_col\");","handlingStrategy":"validation","validationCode":"Type t = schema.findType(\"col\");\nif (!(t instanceof Types.FloatType) && !(t instanceof Types.DoubleType)) { /* use notNull instead */ }","typeGuard":"static boolean supportsNotNan(Type t) { return t.typeId() == Type.TypeID.FLOAT || t.typeId() == Type.TypeID.DOUBLE; }","tryCatchPattern":"try { Expression bound = Binder.bind(struct, Expressions.notNaN(\"col\"), true); } catch (ValidationException e) { /* substitute Expressions.notNull(\"col\") */ }","preventionTips":["Emit notNaN only for float/double columns","Centralize filter construction so type checks happen in one place","Update filters when columns change type"],"tags":["expressions","predicate","validation","type-mismatch"],"backgroundTag":"type-mismatch","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"}