apache/iceberg · error · IllegalArgumentException

No negation for operation

Error message

No negation for operation: ${operation}

What it means

Operation.negate() returns the inverse operation (e.g. EQ -> NOT_EQ, IN -> NOT_IN). Some operations have no logical negation, so the default branch throws IllegalArgumentException listing the operation. Only invertible operations can be negated at the operation level.

Solutions

  1. Check whether the operation has a negation before calling negate() (e.g. switch on op)
  2. Wrap the expression in Expressions.not(expr) instead of relying on operation-level negation if the op is non-invertible
  3. Restrict negation to operations like EQ, NOT_EQ, LT, LT_EQ, GT, GT_EQ, IN, NOT_IN, IS_NULL, NOT_NULL, STARTS_WITH, NOT_STARTS_WITH

Example fix

// before
Operation negated = op.negate(); // throws for IS_NAN
// after
Expression negated = Expressions.not(expr); // safe generic negation
Defensive patterns

Strategy: validation

Validate before calling

Set<Operation> negatable = Set.of(EQ, NOT_EQ, LT, LT_EQ, GT, GT_EQ, IN, NOT_IN, IS_NULL, NOT_NULL, STARTS_WITH, NOT_STARTS_WITH); if (!negatable.contains(op)) { /* use Expressions.not(expr) instead */ }

Type guard

boolean hasNegation = !Set.of(Operation.IS_NAN, Operation.NOT_NAN).contains(op);

Try / catch

try { negated = op.negate(); } catch (IllegalArgumentException e) { negated = null; /* wrap with Expressions.not instead */ }

Prevention

When it happens

Trigger: Calling Operation.negate() on an operation without an inverse, such as IS_NAN/NOT_NAN or STARTS_WITH-family operations not covered by the switch, typically while building NOT(expr) via ExpressionParser or calling expr.negate()/not(...).

Common situations: Rewriting filters by pushing NOT down into predicates; users negating expressions containing operations that lack operation-level negation.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/2c72a3a7053dc368. Report an issue: GitHub.

Appendix: source

Thrown at api/src/main/java/org/apache/iceberg/expressions/Expression.java:95

          return Operation.GT;
        case GT:
          return Operation.LT_EQ;
        case GT_EQ:
          return Operation.LT;
        case EQ:
          return Operation.NOT_EQ;
        case NOT_EQ:
          return Operation.EQ;
        case IN:
          return Operation.NOT_IN;
        case NOT_IN:
          return Operation.IN;
        case STARTS_WITH:
          return Operation.NOT_STARTS_WITH;
        case NOT_STARTS_WITH:
          return Operation.STARTS_WITH;
        default:
          throw new IllegalArgumentException("No negation for operation: " + this);
      }
    }

    /** Returns the equivalent operation when the left and right operands are exchanged. */
    // Allow flipLR as a name because it's a public API
    @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
    public Operation flipLR() {
      switch (this) {
        case LT:
          return Operation.GT;
        case LT_EQ:
          return Operation.GT_EQ;
        case GT:
          return Operation.LT;
        case GT_EQ:
          return Operation.LT_EQ;
        case EQ:
          return Operation.EQ;

View on GitHub (pinned to 86d9c8fc54)