{"record":{"id":"146abab13753ae37","repo":"apache/iceberg","slug":"invalid-operation-for-boundliteralpredicate","errorCode":null,"errorMessage":"Invalid operation for BoundLiteralPredicate: ","messagePattern":"Invalid operation for BoundLiteralPredicate: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java","lineNumber":92,"sourceCode":"    switch (op()) {\n      case LT:\n        return cmp.compare(value, literal.value()) < 0;\n      case LT_EQ:\n        return cmp.compare(value, literal.value()) <= 0;\n      case GT:\n        return cmp.compare(value, literal.value()) > 0;\n      case GT_EQ:\n        return cmp.compare(value, literal.value()) >= 0;\n      case EQ:\n        return cmp.compare(value, literal.value()) == 0;\n      case NOT_EQ:\n        return cmp.compare(value, literal.value()) != 0;\n      case STARTS_WITH:\n        return String.valueOf(value).startsWith((String) literal.value());\n      case NOT_STARTS_WITH:\n        return !String.valueOf(value).startsWith((String) literal.value());\n      default:\n        throw new IllegalStateException(\"Invalid operation for BoundLiteralPredicate: \" + op());\n    }\n  }\n\n  @Override\n  @SuppressWarnings(\"unchecked\")\n  public boolean isEquivalentTo(Expression expr) {\n    if (op() == expr.op()) {\n      BoundLiteralPredicate<?> other = (BoundLiteralPredicate<?>) expr;\n      if (term().isEquivalentTo(other.term())) {\n        // because the term is equivalent, the literal must have the same type, T\n        Literal<T> otherLiteral = (Literal<T>) other.literal();\n        Comparator<T> cmp = literal.comparator();\n        return cmp.compare(literal.value(), otherLiteral.value()) == 0;\n      }\n\n    } else if (expr instanceof BoundLiteralPredicate) {\n      BoundLiteralPredicate<?> other = (BoundLiteralPredicate<?>) expr;\n      if (INTEGRAL_TYPES.contains(term().type().typeId()) && term().isEquivalentTo(other.term())) {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java#L74-L110","documentation":"BoundLiteralPredicate.test(...) supports only literal-comparison operations (LT, LT_EQ, GT, GT_EQ, EQ, NOT_EQ, STARTS_WITH, NOT_STARTS_WITH). Any other operation (e.g. IS_NULL / IN, which belong to other predicate classes) reaching the switch throws this IllegalStateException.","triggerScenarios":"Calling test(value) or matchLiteral on a BoundLiteralPredicate whose op is a non-literal operation, usually after incorrect casting of a generic BoundPredicate to BoundLiteralPredicate without checking isLiteralPredicate().","commonSituations":"Custom predicate evaluation that casts predicates without narrowing; expression rewriting that swaps operations while keeping the literal predicate class.","solutions":["Check pred.isLiteralPredicate() and op() before casting/calling test","Route IS_NULL/NOT_NULL to BoundUnaryPredicate and IN/NOT_IN to BoundSetPredicate","Use ExpressionVisitors.predicates() dispatch instead of manual casts"],"exampleFix":"// before\nBoundLiteralPredicate lit = (BoundLiteralPredicate) pred; // may be IS_NULL etc.\nboolean r = lit.test(value); // throws for non-literal ops\n// after\nif (pred.isLiteralPredicate()) {\n  BoundLiteralPredicate lit = (BoundLiteralPredicate) pred;\n  boolean r = lit.test(value);\n}","handlingStrategy":"type-guard","validationCode":"if (pred.isLiteralPredicate()) { Set.of(Operation.LT, Operation.LT_EQ, Operation.GT, Operation.GT_EQ, Operation.EQ, Operation.NOT_EQ, Operation.STARTS_WITH, Operation.NOT_STARTS_WITH).contains(pred.op()); }","typeGuard":"if (pred instanceof BoundLiteralPredicate lit && Set.of(Operation.EQ, Operation.LT, Operation.GT).contains(lit.op())) { /* safe to test */ }","tryCatchPattern":"try { r = lit.test(value); } catch (IllegalStateException e) { if (e.getMessage().startsWith(\"Invalid operation for BoundLiteralPredicate\")) { /* dispatch to unary/set predicate path */ } else { throw e; } }","preventionTips":["Always narrow via isLiteralPredicate()/isUnaryPredicate()/isSetPredicate()","Use ExpressionVisitors predicate dispatch","Never change a predicate's op after binding"],"tags":["expressions","predicates","invalid-enum-value"],"backgroundTag":"invalid-enum-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}