apache/iceberg · error · UnsupportedOperationException
startsWith expression is not supported by the visitor
Error message
startsWith expression is not supported by the visitor
What it means
The base visitor's default startsWith(BoundReference, Literal) throws UnsupportedOperationException; string-prefix predicates must be explicitly supported by a visitor. Thrown when a STARTS_WITH predicate reaches a visitor that does not override this method.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java:120
public <T> R eq(BoundReference<T> ref, Literal<T> lit) {
return null;
}
public <T> R notEq(BoundReference<T> ref, Literal<T> lit) {
return null;
}
public <T> R in(BoundReference<T> ref, Set<T> literalSet) {
throw new UnsupportedOperationException("In expression is not supported by the visitor");
}
public <T> R notIn(BoundReference<T> ref, Set<T> literalSet) {
throw new UnsupportedOperationException("notIn expression is not supported by the visitor");
}
public <T> R startsWith(BoundReference<T> ref, Literal<T> lit) {
throw new UnsupportedOperationException(
"startsWith expression is not supported by the visitor");
}
public <T> R notStartsWith(BoundReference<T> ref, Literal<T> lit) {
throw new UnsupportedOperationException(
"notStartsWith expression is not supported by the visitor");
}
/**
* Handle a non-reference value in this visitor.
*
* <p>Visitors that require {@link BoundReference references} and not {@link Bound terms} can
* use this method to return a default value for expressions with non-references. The default
* implementation will throw a validation exception because the non-reference is not supported.
*
* @param term a non-reference bound expression
* @param <T> a Java return type
* @return a return value for the visitorView on GitHub (pinned to 86d9c8fc54)
Solutions
- Override startsWith(BoundReference<T> ref, Literal<T> lit) in the visitor to evaluate/translate the prefix predicate
- Catch UnsupportedOperationException and fall back to a conservative evaluation or reject the filter
- Upgrade the visitor/evaluator implementation to a version supporting startsWith
Example fix
// before
// no startsWith override -> default throws
// after
@Override
public <T> R startsWith(BoundReference<T> ref, Literal<T> lit) {
String prefix = (String) lit.value();
return evaluatePrefix(ref.column(), prefix);
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean hasStartsWith = exprOpScan(expr, op -> op == Expression.Operation.STARTS_WITH);
Type guard
static boolean isStartsWith(Predicate p) { return p.op() == Expression.Operation.STARTS_WITH; } Try / catch
try {
return visitor.startsWith(ref, lit);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("startsWith expression is not supported")) {
return conservativeResult(); // e.g. rows=true for evaluators
}
throw e;
} Prevention
- Override startsWith and notStartsWith together for string columns
- Translate LIKE 'x%' filters to startsWith explicitly before pushdown
- Verify third-party evaluators list STARTS_WITH among supported operations
When it happens
Trigger: Visiting an expression built with Expressions.startsWith(col, "prefix") with a visitor lacking a startsWith override, e.g. custom evaluators, older summary evaluators, or engines' pushdown filters hitting an un-updated visitor.
Common situations: Pushing LIKE 'abc%' style filters into custom visitors; third-party catalogs/evaluators written before the startsWith predicate existed.
Related errors
- notStartsWith expression is not supported by the visitor
- ${className} does not implement notNaN
- In expression is not supported by the visitor
- notIn expression is not supported by the visitor
- Visitor %s does not support non-reference: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/43245a4b49bf5e2c.
Report an issue: GitHub.