apache/iceberg · error · UnsupportedOperationException
notStartsWith expression is not supported by the visitor
Error message
notStartsWith expression is not supported by the visitor
What it means
The base visitor's default notStartsWith(BoundReference, Literal) throws UnsupportedOperationException; NOT STARTS_WITH predicates are only handled by visitors that override this method. Thrown when a notStartsWith predicate is visited without an override.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java:125
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 visitor
*/
public <T> R handleNonReference(Bound<T> term) {
throw new ValidationException("Visitor %s does not support non-reference: %s", this, term);
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Override notStartsWith(BoundReference<T> ref, Literal<T> lit) in the visitor (typically the negation of the startsWith result)
- Rewrite the expression with Expressions.rewriteNot so notStartsWith is expressed via supported forms, or fall back conservatively
- Upgrade the evaluator to a version that supports notStartsWith
Example fix
// before
// no notStartsWith override -> default throws
// after
@Override
public <T> R notStartsWith(BoundReference<T> ref, Literal<T> lit) {
return not(startsWithResult(ref, lit));
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean hasNotStartsWith = exprOpScan(expr, op -> op == Expression.Operation.NOT_STARTS_WITH);
Type guard
static boolean isNotStartsWith(Predicate p) { return p.op() == Expression.Operation.NOT_STARTS_WITH; } Try / catch
try {
return visitor.notStartsWith(ref, lit);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("notStartsWith expression is not supported")) {
return not(visitor.startsWith(ref, lit));
}
throw e;
} Prevention
- Override notStartsWith whenever startsWith is implemented
- Run Expressions.rewriteNot on filters before evaluating with limited visitors
- Include NOT LIKE prefix filters in evaluator test matrices
When it happens
Trigger: Visiting Expressions.notStartsWith(col, "prefix") with a visitor lacking a notStartsWith override — commonly custom evaluators or engine integrations predating the predicate.
Common situations: Pushing NOT LIKE 'abc%' filters into older visitor implementations; evaluators updated for startsWith but not its negation.
Related errors
- startsWith 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/e3abd4b3dba996cc.
Report an issue: GitHub.