{"record":{"id":"6bdd56f12674e265","repo":"apache/iceberg","slug":"cannot-convert-unknown-expression","errorCode":null,"errorMessage":"Cannot convert unknown expression: ","messagePattern":"Cannot convert unknown expression: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":416,"sourceCode":"          return org.apache.iceberg.expressions.Expressions.hour(colName);\n        case \"truncate\":\n          return org.apache.iceberg.expressions.Expressions.truncate(colName, findWidth(transform));\n        case \"zorder\":\n          return new Zorder(\n              Stream.of(transform.references())\n                  .map(ref -> DOT.join(ref.fieldNames()))\n                  .map(org.apache.iceberg.expressions.Expressions::ref)\n                  .collect(Collectors.toList()));\n        default:\n          throw new UnsupportedOperationException(\"Transform is not supported: \" + transform);\n      }\n\n    } else if (expr instanceof NamedReference) {\n      NamedReference ref = (NamedReference) expr;\n      return org.apache.iceberg.expressions.Expressions.ref(DOT.join(ref.fieldNames()));\n\n    } else {\n      throw new UnsupportedOperationException(\"Cannot convert unknown expression: \" + expr);\n    }\n  }\n\n  /**\n   * Converts Spark transforms into a {@link PartitionSpec}.\n   *\n   * @param schema the table schema\n   * @param partitioning Spark Transforms\n   * @return a PartitionSpec\n   */\n  public static PartitionSpec toPartitionSpec(Schema schema, Transform[] partitioning) {\n    if (partitioning == null || partitioning.length == 0) {\n      return PartitionSpec.unpartitioned();\n    }\n\n    PartitionSpec.Builder builder = PartitionSpec.builderFor(schema);\n    for (Transform transform : partitioning) {\n      Preconditions.checkArgument(","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L398-L434","documentation":"Spark3Util.toIcebergTerm converts Spark V2 expression trees (org.apache.spark.sql.connector.expressions.Expression) into Iceberg expressions. It handles Literal, And, Or, Not, NullsOrdering/options and NamedReference; anything else is untranslatable, so it throws UnsupportedOperationException. This guards DESCRIBE TABLE / partition-spec conversion paths from silently producing wrong filters.","triggerScenarios":"Calling toIcebergTerm with a Spark expression not in the supported set, e.g. a SortOrder, Cast, UserDefinedExpression, or other NamedExpression/transform produced by Spark's connector API instead of a simple literal/comparison/column reference.","commonSituations":"Running DESCRIBE TABLE EXTENDED or converting a Spark filter/pushdown on a table whose partition transforms or expressions include constructs Iceberg's Spark conversion doesn't support; typically after Spark version changes or custom catalogs supplying exotic expressions.","solutions":["Inspect the failing expression printed in the message; rewrite the query/DDL to use only simple column references, literals and AND/OR/NOT predicates supported by Iceberg","Check whether the expression is a transform/sort-order that should go through Spark3Util.toIcebergTerm's transform path or V2Expressions, not the predicate path","Upgrade or patch Iceberg's Spark module to a version that supports this expression type","If authoring the caller, wrap toIcebergTerm in try/catch for UnsupportedOperationException and degrade to non-pushed filter"],"exampleFix":"// before\nExpression term = Spark3Util.toIcebergTerm(sparkExpr); // throws on Cast/SortOrder\n// after\nExpression term;\ntry {\n  term = Spark3Util.toIcebergTerm(sparkExpr);\n} catch (UnsupportedOperationException e) {\n  term = Expressions.alwaysTrue(); // fall back: evaluate filter in Spark\n}","handlingStrategy":"try-catch","validationCode":"// Check the expression is one of the supported shapes\nboolean supported = expr instanceof Literal || expr instanceof And || expr instanceof Or\n    || expr instanceof Not || expr instanceof NamedReference;\nif (!supported) throw new IllegalArgumentException(\"Unsupported Spark expression: \" + expr);","typeGuard":"boolean isConvertible(org.apache.spark.sql.connector.expressions.Expression e) {\n  return e instanceof Literal || e instanceof And || e instanceof Or\n      || e instanceof Not || e instanceof NamedReference;\n}","tryCatchPattern":"try {\n  Expression term = Spark3Util.toIcebergTerm(expr);\n} catch (UnsupportedOperationException e) {\n  LOG.warn(\"Falling back to Spark-side filtering: {}\", e.getMessage());\n  // keep predicate un-pushed\n}","preventionTips":["Only pass literal/AND/OR/NOT/column-reference expressions to toIcebergTerm","Keep Spark and Iceberg connector versions aligned","Guard new expression sources with an instanceof check before conversion"],"tags":["spark","expression-conversion","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}