{"record":{"id":"c08f2c534c4256c4","repo":"apache/iceberg","slug":"cannot-convert-term-to-sql","errorCode":null,"errorMessage":"Cannot convert term to SQL: ","messagePattern":"Cannot convert term to SQL: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":697,"sourceCode":"        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(\", \"));\n    }\n\n    private static String sqlString(org.apache.iceberg.expressions.Literal<?> lit) {\n      if (lit.value() instanceof String) {\n        return \"'\" + lit.value() + \"'\";\n      } else if (lit.value() instanceof ByteBuffer) {\n        byte[] bytes = ByteBuffers.toByteArray((ByteBuffer) lit.value());\n        return \"X'\" + BaseEncoding.base16().encode(bytes) + \"'\";\n      } else {\n        return lit.value().toString();\n      }","sourceCodeStart":679,"sourceCodeEnd":715,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L679-L715","documentation":"DescribeExpressionVisitor.sqlString(UnboundTerm) renders a predicate term as SQL: a NamedReference renders as its column name and an UnboundTransform as transform(col). Any other term (e.g. AccessorReference or bound terms) throws UnsupportedOperationException 'Cannot convert term to SQL'.","triggerScenarios":"Rendering an Iceberg predicate whose term is not a plain column reference or unbound transform — e.g. terms built over struct accessors or custom term implementations passed into the describe visitor.","commonSituations":"DESCRIBE output for filters on nested fields or exotic terms; tooling that feeds arbitrary UnboundTerm objects into Spark3Util's describe path.","solutions":["Use predicates over top-level columns or unbound transforms so terms render as ref or transform(col)","Extend the visitor (or write a custom ExpressionVisitor) if nested/marshalled term rendering is required","Flatten nested-field predicates into a supported form before rendering"],"exampleFix":"// before\nsqlString(customTerm) // throws\n// after\nif (term instanceof NamedReference || term instanceof UnboundTransform) {\n  sqlString(term);\n} else {\n  throw new IllegalArgumentException(\"Unsupported term: \" + term);\n}","handlingStrategy":"type-guard","validationCode":"boolean ok = term instanceof org.apache.iceberg.expressions.NamedReference\n    || term instanceof org.apache.iceberg.expressions.UnboundTransform;\nif (!ok) throw new IllegalArgumentException(\"Term not renderable as SQL: \" + term);","typeGuard":"boolean isRenderableTerm(org.apache.iceberg.expressions.Term t) {\n  return t instanceof org.apache.iceberg.expressions.NamedReference\n      || t instanceof org.apache.iceberg.expressions.UnboundTransform;\n}","tryCatchPattern":"try {\n  return sqlString(term);\n} catch (UnsupportedOperationException e) {\n  return term.toString();\n}","preventionTips":["Build predicates with Expressions.column/transform-based terms only","Avoid custom Term implementations in code that must render SQL","Verify terms are unbound before rendering"],"tags":["spark","term","sql-rendering"],"backgroundTag":"unsupported-operation","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"}