apache/iceberg · error · java.lang.UnsupportedOperationException
Cannot convert term to SQL: %s
Error message
Cannot convert term to SQL: %s
What it means
sqlString in DescribeExpressionVisitor renders only NamedReference and UnboundTransform terms; any other UnboundTerm (e.g. a constant/extract term) throws UnsupportedOperationException because it has no direct SQL rendering.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:693
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)
Solutions
- Restrict predicates to column or transform terms before describing
- Catch UnsupportedOperationException and fall back to a generic string rendering of the expression
- Extend the visitor (fork or newer version) to handle the specific term type
Example fix
// before
throw new UnsupportedOperationException("Cannot convert term to SQL: " + term);
// after
} else if (term instanceof UnboundExtract) {
UnboundExtract<?> extract = (UnboundExtract<?>) term;
return "extract(" + extract.ref().name() + ")";
} else {
throw new UnsupportedOperationException("Cannot convert term to SQL: " + term);
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean ok = term instanceof NamedReference || term instanceof UnboundTransform;
Type guard
boolean isRenderableTerm(UnboundTerm<?> t) { return t instanceof NamedReference || t instanceof UnboundTransform; } Try / catch
try { return Spark3Util.describe(expr); } catch (UnsupportedOperationException e) { return expr.toString(); } Prevention
- Build filter predicates only on column references or transforms
- Avoid literal/extract terms when SQL rendering is required
- Write a custom ExpressionVisitor if richer term rendering is needed
When it happens
Trigger: Calling Spark3Util.describe on a predicate whose term is neither a plain column reference nor a transform, e.g. predicates built over Literal references or other exotic terms.
Common situations: Programmatically constructed expressions with unusual terms being pretty-printed to SQL for catalog partition predicates or metadata filters.
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
- Cannot convert predicate to SQL: %s
- Cannot convert type to SQL: %s
- Unsupported format in USING:
- Cannot convert bound predicates to SQL
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/b0bd3727d13f1365.
Report an issue: GitHub.