{"record":{"id":"644c7ad6fe344e8f","repo":"apache/iceberg","slug":"cannot-convert-predicate-to-sql-s","errorCode":null,"errorMessage":"Cannot convert predicate to SQL: %s","messagePattern":"Cannot convert predicate to SQL: (.+?)","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":682,"sourceCode":"          return sqlString(pred.term()) + \" <= \" + sqlString(pred.literal());\n        case GT:\n          return sqlString(pred.term()) + \" > \" + sqlString(pred.literal());\n        case GT_EQ:\n          return sqlString(pred.term()) + \" >= \" + sqlString(pred.literal());\n        case EQ:\n          return sqlString(pred.term()) + \" = \" + sqlString(pred.literal());\n        case NOT_EQ:\n          return sqlString(pred.term()) + \" != \" + sqlString(pred.literal());\n        case STARTS_WITH:\n          return sqlString(pred.term()) + \" LIKE '\" + pred.literal().value() + \"%'\";\n        case NOT_STARTS_WITH:\n          return sqlString(pred.term()) + \" NOT LIKE '\" + pred.literal().value() + \"%'\";\n        case IN:\n          return sqlString(pred.term()) + \" IN (\" + sqlString(pred.literals()) + \")\";\n        case NOT_IN:\n          return sqlString(pred.term()) + \" NOT IN (\" + sqlString(pred.literals()) + \")\";\n        default:\n          throw new UnsupportedOperationException(\"Cannot convert predicate to SQL: \" + pred);\n      }\n    }\n\n    private static <T> String sqlString(UnboundTerm<T> term) {\n      if (term instanceof org.apache.iceberg.expressions.NamedReference) {\n        return term.ref().name();\n      } else if (term instanceof UnboundTransform) {\n        UnboundTransform<?, ?> transform = (UnboundTransform<?, ?>) term;\n        return transform.transform().toString() + \"(\" + transform.ref().name() + \")\";\n      } else {\n        throw new UnsupportedOperationException(\"Cannot convert term to SQL: \" + term);\n      }\n    }\n\n    private static <T> String sqlString(List<org.apache.iceberg.expressions.Literal<T>> literals) {\n      return literals.stream()\n          .map(DescribeExpressionVisitor::sqlString)\n          .collect(Collectors.joining(\", \"));","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L664-L700","documentation":"The unbound-predicate branch of DescribeExpressionVisitor throws when the predicate's operator is not one of the explicitly rendered SQL operators (IS_NULL, NOT_NULL, EQ, LT, LTE, GT, GTE, STARTS_WITH, NOT_STARTS_WITH, LIKE, NOT_LIKE, IN, NOT_IN).","triggerScenarios":"Calling Spark3Util.describe with an unbound predicate whose op() is unsupported, e.g. Expressions.startsWith variants not covered in older versions, COUNT/aggregate predicates, or custom predicate ops.","commonSituations":"Rendering user filters that use operators without direct SQL equivalents (e.g. 'str.contains' composed as predicate variants, nan/not-nan checks) for SHOW CREATE TABLE or EXPLAIN-style output.","solutions":["Pre-filter or transform the expression to only supported operators before calling describe","Wrap the call in try/catch for UnsupportedOperationException and fall back to expression.toString()","Upgrade Iceberg — newer versions add more operator cases (e.g. STARTS_WITH was added over time)"],"exampleFix":"// before\nString sql = Spark3Util.describe(Expressions.contains(\"col\", \"x\")); // throws\n// after\nString sql;\ntry { sql = Spark3Util.describe(expr); }\ncatch (UnsupportedOperationException e) { sql = expr.toString(); }","handlingStrategy":"try-catch","validationCode":"Set<Predicate.Op> SUPPORTED = Set.of(IS_NULL, NOT_NULL, EQ, LT, LTE, GT, GTE, IN, NOT_IN, LIKE, NOT_LIKE);\n// check pred.op() before describing","typeGuard":"boolean isSqlRenderableOp(Predicate p) { return SUPPORTED_OPS.contains(p.op()); }","tryCatchPattern":"try { return Spark3Util.describe(pred); } catch (UnsupportedOperationException e) { return pred.toString(); }","preventionTips":["Restrict user-facing filters to operators with SQL equivalents","Fall back to Expression.toString for unsupported operators","Upgrade Iceberg to pick up newly supported operator cases"],"tags":["spark","expressions","sql"],"backgroundTag":"unsupported-operation","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"}