{"record":{"id":"7213c0e0509d0ed4","repo":"apache/iceberg","slug":"s-cannot-be-negated","errorCode":null,"errorMessage":"%s cannot be negated","messagePattern":"(.+?) cannot be negated","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/Expression.java","lineNumber":131,"sourceCode":"          return Operation.EQ;\n        case NOT_EQ:\n          return Operation.NOT_EQ;\n        case AND:\n          return Operation.AND;\n        case OR:\n          return Operation.OR;\n        default:\n          throw new IllegalArgumentException(\"No left-right flip for operation: \" + this);\n      }\n    }\n  }\n\n  /** Returns the operation for an expression node. */\n  Operation op();\n\n  /** Returns the negation of this expression, equivalent to not(this). */\n  default Expression negate() {\n    throw new UnsupportedOperationException(String.format(\"%s cannot be negated\", this));\n  }\n\n  /**\n   * Returns whether this expression will accept the same values as another.\n   *\n   * <p>If this returns true, the expressions are guaranteed to return the same evaluation for the\n   * same input. However, if this returns false the expressions may return the same evaluation for\n   * the same input. That is, expressions may be equivalent even if this returns false.\n   *\n   * <p>For best results, rewrite not and bind expressions before calling this method.\n   *\n   * @param other another expression\n   * @return true if the expressions are equivalent\n   */\n  default boolean isEquivalentTo(Expression other) {\n    // only bound predicates can be equivalent\n    return false;\n  }","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/Expression.java#L113-L149","documentation":"Expression.negate() is a default method on the Expression interface returning the negation of the expression. Not every concrete Expression implements it (e.g. some aggregate or bound expressions), so the default body throws UnsupportedOperationException naming the expression. Expressions built via Expressions.not() avoid this by wrapping in Not expressions.","triggerScenarios":"Calling negate() directly on an Expression implementation that does not override it — e.g. bound expressions, aggregates, or custom Expression classes — while trying to invert a filter.","commonSituations":"Inverting user filters for pushdown or query rewriting; calling negate() on BoundExpression (bind-then-negate pattern) rather than negating before binding.","solutions":["Negate the unbound expression with Expressions.not(expr) instead of calling negate() on the bound one","Negate before binding: Expressions.not(expr) then Binder.bind(schema, notExpr)","Implement negate() in custom Expression subclasses","Check instanceof BoundExpression and unwrap to the original unbound expression first"],"exampleFix":"// before\nExpression notExpr = Binder.bind(schema, expr).negate(); // throws\n// after\nExpression notExpr = Binder.bind(schema, Expressions.not(expr));","handlingStrategy":"fallback","validationCode":"if (expr instanceof BoundExpression) { /* negate the unbound original instead */ }","typeGuard":"function negatable(e) { return !(e instanceof org.apache.iceberg.expressions.BoundExpression); }","tryCatchPattern":"try { notExpr = expr.negate(); } catch (UnsupportedOperationException e) { notExpr = Expressions.not(((BoundExpression) expr).originalExpr()); }","preventionTips":["Negate expressions before binding, using Expressions.not()","Avoid calling negate() on bound expressions and aggregates","Implement negate() in any custom Expression subclass"],"tags":["expressions","negation","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}