apache/iceberg · error · UnsupportedOperationException
Cannot convert term to SQL
Error message
Cannot convert term to SQL: ${term} What it means
sqlString(UnboundTerm<T>) can render only a NamedReference (column name) or an UnboundTransform (transform(col)). Any other term type reaching this visitor has no SQL representation and throws UnsupportedOperationException with the term's toString.
Solutions
- Ensure predicate terms are NamedReference or UnboundTransform before describing
- Extract the column/transform yourself and build a new expression with Expressions.transform or plain column names
- Skip describing or implement custom rendering for unsupported term types
Example fix
// before
String sql = Spark3Util.describe(schema, someCustomTermPredicate); // throws
// after
Expression rebuilt = Expressions.equal("col", 42); // plain NamedReference term
String sql = Spark3Util.describe(schema, rebuilt); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(term instanceof NamedReference) && !(term instanceof UnboundTransform)) { throw new IllegalArgumentException("Unsupported term: " + term); } Type guard
boolean isSqlRenderableTerm(Term t) { return t instanceof NamedReference || t instanceof UnboundTransform; } Try / catch
try { return Spark3Util.describe(schema, expr); } catch (UnsupportedOperationException e) { log.warn("Term not renderable: {}", e.getMessage()); return null; } Prevention
- Build describe-input expressions only from column refs and Expressions.transform
- Do not pass bound terms into unbound description APIs
- Rebuild custom terms as UnboundTransform before describing
When it happens
Trigger: Calling Spark3Util.describe(schema, expr) where the expression references a term that is neither a plain column nor an unbound transform — e.g. bound terms, literal-only terms, or custom UnboundTerm implementations.
Common situations: Describing expressions containing custom or bound terms; passing terms from residual/leftover filters into describe; using a term type added after this visitor was written.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot convert bound predicates to SQL
- Altering a view is not supported by catalog:
- Altering a view is not supported by catalog
- Altering a view is not supported by catalog
- Altering a view is not supported by catalog
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9dc1f1964fcc57bc.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:744
case NOT_STARTS_WITH:
return sqlString(pred.term()) + " NOT LIKE '" + pred.literal().value() + "%'";
case IN:
return sqlString(pred.term()) + " IN (" + sqlString(pred.literals()) + ")";
case NOT_IN:
return sqlString(pred.term()) + " NOT IN (" + sqlString(pred.literals()) + ")";
default:
throw new UnsupportedOperationException("Cannot convert predicate to SQL: " + pred);
}
}
private static <T> String sqlString(UnboundTerm<T> term) {
if (term instanceof org.apache.iceberg.expressions.NamedReference) {
return term.ref().name();
} else if (term instanceof UnboundTransform) {
UnboundTransform<?, ?> transform = (UnboundTransform<?, ?>) term;
return transform.transform().toString() + "(" + transform.ref().name() + ")";
} else {
throw new UnsupportedOperationException("Cannot convert term to SQL: " + term);
}
}
private static <T> String sqlString(List<org.apache.iceberg.expressions.Literal<T>> literals) {
return literals.stream()
.map(DescribeExpressionVisitor::sqlString)
.collect(Collectors.joining(", "));
}
private static String sqlString(org.apache.iceberg.expressions.Literal<?> lit) {
if (lit.value() instanceof String) {
return "'" + lit.value() + "'";
} else if (lit.value() instanceof ByteBuffer) {
byte[] bytes = ByteBuffers.toByteArray((ByteBuffer) lit.value());
return "X'" + BaseEncoding.base16().encode(bytes) + "'";
} else {
return lit.value().toString();
}View on GitHub (pinned to 86d9c8fc54)