{"record":{"id":"443d5d81155ea23d","repo":"apache/iceberg","slug":"in-expression-is-not-supported-by-the-visitor","errorCode":null,"errorMessage":"In expression is not supported by the visitor","messagePattern":"In expression is not supported by the visitor","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java","lineNumber":112,"sourceCode":"\n    public <T> R gt(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R gtEq(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R eq(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R notEq(BoundReference<T> ref, Literal<T> lit) {\n      return null;\n    }\n\n    public <T> R in(BoundReference<T> ref, Set<T> literalSet) {\n      throw new UnsupportedOperationException(\"In expression is not supported by the visitor\");\n    }\n\n    public <T> R notIn(BoundReference<T> ref, Set<T> literalSet) {\n      throw new UnsupportedOperationException(\"notIn expression is not supported by the visitor\");\n    }\n\n    public <T> R startsWith(BoundReference<T> ref, Literal<T> lit) {\n      throw new UnsupportedOperationException(\n          \"startsWith expression is not supported by the visitor\");\n    }\n\n    public <T> R notStartsWith(BoundReference<T> ref, Literal<T> lit) {\n      throw new UnsupportedOperationException(\n          \"notStartsWith expression is not supported by the visitor\");\n    }\n\n    /**\n     * Handle a non-reference value in this visitor.","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java#L94-L130","documentation":"The base expression visitor's default in(BoundReference, Set) throws UnsupportedOperationException because IN predicates are optional for visitors. It is thrown when a visitor that has not overridden the IN case encounters an in predicate. Visitors must opt in by overriding this method.","triggerScenarios":"Visiting an expression containing in(col, values) (e.g. from filter \"col IN (...)\") with a visitor class that does not override in(BoundReference<T>, Set<T>), such as a custom ExpressionVisitor base or an older evaluator predating IN support.","commonSituations":"Custom scan planners or predicate translators written before Iceberg added IN predicates; passing user SQL filters with IN clauses through an old visitor implementation.","solutions":["Override in(BoundReference<T> ref, Set<T> literalSet) in the visitor to translate/evaluate the IN predicate (often rewritten as a chain of OR equalities)","Alternatively rewrite the expression with ExpressionUtil or rewriteNot/in expansion before visiting if the visitor only supports eq","Update to a newer version of the evaluator/visitor implementation that supports IN"],"exampleFix":"// before\n// visitor without in() hits default throw\n// after\n@Override\npublic <T> R in(BoundReference<T> ref, Set<T> literalSet) {\n  return literalSet.stream().map(v -> eqResult(ref, v)).reduce(or, combine); // or direct IN handling\n}","handlingStrategy":"try-catch","validationCode":"// detect IN predicates before visiting\nboolean hasIn = ExpressionVisitors.visit(expr, new ExpressionVisitors.ExpressionVisitor<Boolean>() {\n  @Override public Boolean predicate(UnboundPredicate<?> p) { return p.op() == Expression.Operation.IN; }\n  @Override public Boolean alwaysTrue() { return false; }\n  @Override public Boolean alwaysFalse() { return false; }\n  @Override public Boolean not(Boolean r) { return r; }\n  @Override public Boolean and(Boolean l, Boolean r) { return l || r; }\n  @Override public Boolean or(Boolean l, Boolean r) { return l || r; }\n});","typeGuard":"static boolean isInPredicate(Predicate p) { return p.op() == Expression.Operation.IN; }","tryCatchPattern":"try {\n  return visitor.in(ref, literalSet);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"In expression is not supported\")) {\n    return expandInAsOr(ref, literalSet); // rewrite to OR of eq\n  }\n  throw e;\n}","preventionTips":["Always override in() and notIn() together in custom visitors","Rewrite user SQL filters containing IN clauses before passing them to old evaluators","Pin visitor/evaluator implementations to an Iceberg version that supports IN predicates"],"tags":["java","expressions","visitor","in-predicate"],"backgroundTag":"method-not-implemented","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}