{"record":{"id":"5aedb86c4a94392c","repo":"apache/iceberg","slug":"cannot-get-nan-value-for-type","errorCode":null,"errorMessage":"Cannot get NaN value for type ","messagePattern":"Cannot get NaN value for type ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"orc/src/main/java/org/apache/iceberg/orc/ExpressionToSearchArgument.java","lineNumber":148,"sourceCode":"  }\n\n  @Override\n  public <T> Action isNaN(Bound<T> expr) {\n    return () ->\n        this.builder.equals(\n            idToColumnName.get(expr.ref().fieldId()),\n            type(expr.ref().type()),\n            literal(expr.ref().type(), getNaNForType(expr.ref().type())));\n  }\n\n  private Object getNaNForType(Type type) {\n    switch (type.typeId()) {\n      case FLOAT:\n        return Float.NaN;\n      case DOUBLE:\n        return Double.NaN;\n      default:\n        throw new IllegalArgumentException(\"Cannot get NaN value for type \" + type.typeId());\n    }\n  }\n\n  @Override\n  public <T> Action notNaN(Bound<T> expr) {\n    return () -> {\n      this.builder.startOr();\n      isNull(expr).invoke();\n      this.builder.startNot();\n      isNaN(expr).invoke();\n      this.builder.end(); // end NOT\n      this.builder.end(); // end OR\n    };\n  }\n\n  @Override\n  public <T> Action lt(Bound<T> expr, Literal<T> lit) {\n    return () ->","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/orc/src/main/java/org/apache/iceberg/orc/ExpressionToSearchArgument.java#L130-L166","documentation":"ExpressionToSearchArgument.getNaNForType() produces the NaN sentinel for NaN predicate pushdown and only supports FLOAT and DOUBLE ORC columns. When a NaN filter is applied to any other column type, IllegalArgumentException(\"Cannot get NaN value for type X\") is thrown since NaN is meaningless there.","triggerScenarios":"Applying an isNotNaN()/isNaN() filter (e.g., Spark's isNan(col)) to a non-float/double column (decimal, int, string) that gets pushed down to ORC search arguments.","commonSituations":"Spark SQL isNan() on decimal or integer columns with ORC tables and filter pushdown enabled; schemas changed from float to decimal after queries were written.","solutions":["Apply isNaN()/isNotNaN() only to FLOAT or DOUBLE columns; cast or change the column type.","Rewrite the filter as a null/equality check suitable for the column's actual type.","Disable the NaN pushdown (turn off ORC filter pushdown) if the query cannot change.","Cast the column to double in the query so the NaN predicate has a valid type."],"exampleFix":"// before\ndf.filter(\"isnan(dec_col)\") // dec_col DECIMAL -> Cannot get NaN value for type DECIMAL\n// after\ndf.filter(\"dec_col IS NULL OR cast(dec_col AS DOUBLE) = cast(dec_col AS DOUBLE) == false OR isnan(cast(dec_col AS DOUBLE))\")\n// or simply restrict isnan to float/double columns","handlingStrategy":"validation","validationCode":"// only apply NaN filters to float/double columns\nif (!(exprType instanceof Types.FloatType || exprType instanceof Types.DoubleType)) {\n  throw new IllegalArgumentException(\"isNaN requires float/double, got \" + exprType);\n}","typeGuard":"boolean nanCapable = t instanceof Types.FloatType || t instanceof Types.DoubleType;","tryCatchPattern":"try { scan.filter(isNaN(col)); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Cannot get NaN value\")) { /* use type-appropriate filter */ } throw e; }","preventionTips":["Use isNan only on float/double columns","Cast decimals to double before NaN checks","Validate filter columns' types in query builders","Keep pushdown types in mind when writing SQL"],"tags":["orc","pushdown","predicate","type-mismatch"],"backgroundTag":"invalid-argument-value","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"}