apache/iceberg · error · IllegalArgumentException
No left-right flip for operation: ${operation}
Error message
No left-right flip for operation: ${operation} What it means
Operation.flipLR() returns the equivalent operation with left/right operands exchanged (LT -> GT, LT_EQ -> GT_EQ, EQ stays EQ, AND/OR stay the same). Operations without a meaningful flip throw IllegalArgumentException. It only makes sense for binary comparison operations.
Source
Thrown at api/src/main/java/org/apache/iceberg/expressions/Expression.java:121
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;
case NOT_EQ:
return Operation.NOT_EQ;
case AND:
return Operation.AND;
case OR:
return Operation.OR;
default:
throw new IllegalArgumentException("No left-right flip for operation: " + this);
}
}
}
/** Returns the operation for an expression node. */
Operation op();
/** Returns the negation of this expression, equivalent to not(this). */
default Expression negate() {
throw new UnsupportedOperationException(String.format("%s cannot be negated", this));
}
/**
* Returns whether this expression will accept the same values as another.
*
* <p>If this returns true, the expressions are guaranteed to return the same evaluation for the
* same input. However, if this returns false the expressions may return the same evaluation for
* the same input. That is, expressions may be equivalent even if this returns false.View on GitHub (pinned to 86d9c8fc54)
Solutions
- Only call flipLR() on comparison operations (EQ, NOT_EQ, LT, LT_EQ, GT, GT_EQ); symmetric ops AND/OR also support it
- Check op kind (isPredicate/isComparison) before flipping
- Skip or handle other operations explicitly in the rewriter
Example fix
// before
Operation flipped = op.flipLR(); // throws for IS_NULL
// after
if (op == Operation.EQ || op == Operation.NOT_EQ || op == Operation.LT ||
op == Operation.LT_EQ || op == Operation.GT || op == Operation.GT_EQ ||
op == Operation.AND || op == Operation.OR) {
Operation flipped = op.flipLR();
} Defensive patterns
Strategy: validation
Validate before calling
EnumSet<Operation> flippable = EnumSet.of(EQ, NOT_EQ, LT, LT_EQ, GT, GT_EQ, AND, OR); if (!flippable.contains(op)) { /* skip flip */ } Type guard
boolean canFlip = flippable.contains(op);
Try / catch
try { flipped = op.flipLR(); } catch (IllegalArgumentException e) { /* keep original operand order */ } Prevention
- Call flipLR only for comparison operations
- Handle AND/OR and symmetric operations explicitly in normalizers
- Guard rewriters with an op-kind check before transformation
When it happens
Trigger: Calling Operation.flipLR() on a non-comparison operation such as IS_NULL, IN, AND on non-symmetric context, or any unary/set operation, when normalizing expressions (e.g. moving a literal to the other side of a predicate).
Common situations: Expression normalization/optimization code that rewrites 'literal op column' into 'column flippedOp literal' but encounters a non-comparison operation.
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
- Invalid operation type: %s
- No negation for operation: ${operation}
- Invalid distribution mode: %s
- Invalid file format: %s
- Invalid rewrite job order name: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9928df54c269aea3.
Report an issue: GitHub.