apache/iceberg · error · UnsupportedOperationException
notIn expression is not supported by the visitor
Error message
notIn expression is not supported by the visitor
What it means
The base visitor's default notIn(BoundReference, Set) throws UnsupportedOperationException, marking NOT IN predicates as unsupported unless the visitor opts in. Thrown when visiting an expression containing notIn without an override.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java:116
public <T> R gtEq(BoundReference<T> ref, Literal<T> lit) {
return null;
}
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.View on GitHub (pinned to 86d9c8fc54)
Solutions
- Override notIn(BoundReference<T>, Set<T>) in the visitor (typically as NOT of the in() result)
- Rewrite the expression (e.g. via Expressions.rewriteNot) so notIn is decomposed into supported predicates
- Upgrade the evaluator implementation to one supporting notIn
Example fix
// before
// no override -> default throws
// after
@Override
public <T> R notIn(BoundReference<T> ref, Set<T> literalSet) {
return not(inResult(ref, literalSet));
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean hasNotIn = exprOpScan(expr, op -> op == Expression.Operation.NOT_IN);
Type guard
static boolean isNotInPredicate(Predicate p) { return p.op() == Expression.Operation.NOT_IN; } Try / catch
try {
return visitor.notIn(ref, literalSet);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("notIn expression is not supported")) {
return not(visitor.in(ref, literalSet));
}
throw e;
} Prevention
- Override notIn() whenever you override in()
- Apply Expressions.rewriteNot to push NOT operators down before visiting
- Test custom visitors with NOT IN filters from engine pushdown
When it happens
Trigger: Visiting an expression containing notIn(col, values) (e.g. filter "col NOT IN (...)") with a visitor that does not override notIn(BoundReference<T>, Set<T>).
Common situations: Custom predicate translators or evaluators built before notIn was added to the visitor API encountering newer filters from engines.
Related errors
- ${className} does not implement notNaN
- In expression is not supported by the visitor
- startsWith expression is not supported by the visitor
- notStartsWith 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/d52059f7a77c5016.
Report an issue: GitHub.