{"record":{"id":"4d7c90e6b4906373","repo":"apache/iceberg","slug":"invalid-operation-for-boundsetpredicate","errorCode":null,"errorMessage":"Invalid operation for BoundSetPredicate: ","messagePattern":"Invalid operation for BoundSetPredicate: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java","lineNumber":65,"sourceCode":"\n  @Override\n  public BoundSetPredicate<T> asSetPredicate() {\n    return this;\n  }\n\n  public Set<T> literalSet() {\n    return literalSet;\n  }\n\n  @Override\n  public boolean test(T value) {\n    switch (op()) {\n      case IN:\n        return value != null && literalSet.contains(value);\n      case NOT_IN:\n        return value == null || !literalSet.contains(value);\n      default:\n        throw new IllegalStateException(\"Invalid operation for BoundSetPredicate: \" + op());\n    }\n  }\n\n  @Override\n  public boolean isEquivalentTo(Expression other) {\n    // only check bound set predicate; binding will convert sets of a single item to a literal\n    // predicate\n    if (op() == other.op()) {\n      BoundSetPredicate<?> pred = (BoundSetPredicate<?>) other;\n      return literalSet().equals(pred.literalSet());\n    }\n\n    return false;\n  }\n\n  @Override\n  public String toString() {\n    switch (op()) {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java#L47-L83","documentation":"BoundSetPredicate.test() only supports the IN and NOT_IN operations. If the bound predicate carries any other operation, the switch falls through to default and throws IllegalStateException. This is an internal invariant violation: a BoundSetPredicate should only ever be constructed with IN or NOT_IN.","triggerScenarios":"Evaluating a BoundSetPredicate whose op() is not IN/NOT_IN — practically only possible via corrupted construction, misuse of internal APIs, or a bug in a custom expression rewrite that changed the operation on a set predicate.","commonSituations":"Custom expression rewriting/transformation code that swaps operations on predicates without preserving the predicate class/operation pairing.","solutions":["Only construct or rewrite BoundSetPredicate with Operation.IN or Operation.NOT_IN","Check op() before invoking test() if operations may have been transformed","Report a bug if triggered by stock Iceberg binding/evaluation"],"exampleFix":"// before\npred.asSetPredicate().test(value);\n// after\nif (pred.op() == Operation.IN || pred.op() == Operation.NOT_IN) {\n  pred.asSetPredicate().test(value);\n}","handlingStrategy":"validation","validationCode":"if (pred.op() != Operation.IN && pred.op() != Operation.NOT_IN) { throw new IllegalArgumentException(\"BoundSetPredicate requires IN/NOT_IN\"); }","typeGuard":"boolean evaluableSet = p.op() == Operation.IN || p.op() == Operation.NOT_IN;","tryCatchPattern":"try { result = setPred.test(value); } catch (IllegalStateException e) { /* corrupt operation: log and fail fast */ }","preventionTips":["Never mutate op() on constructed predicates in custom rewrites","Rebind expressions after transformation instead of patching operations","Treat this as an internal bug if triggered by stock APIs"],"tags":["expressions","evaluation","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}