apache/iceberg · error · UnsupportedOperationException
Cannot sanitize unsupported predicate type
Error message
Cannot sanitize unsupported predicate type: ${operation} What it means
The unbound-predicate sanitizer handles only literal-bearing predicate operations (isNull, notNull, eq, lt, in, etc.); anything reaching the switch's default branch throws this UnsupportedOperationException because its literals cannot be sanitized.
Solutions
- Upgrade Iceberg to a version whose sanitizer covers the operation in use
- Pre-filter: check pred.op() and leave unsupported predicates unsanitized or handle them explicitly
- Sanitize literals yourself and rebuild the predicate with supported ops only
Example fix
// before
String safe = ExpressionUtil.sanitize(ExpressionUtil.predicate("startsWith", "col", "abc"), now, today);
// after
if (pred.op() == Expression.Operation.STARTS_WITH) { /* handle explicitly */ }
else { ExpressionUtil.sanitize(pred, now, today); } Defensive patterns
Strategy: try-catch
Validate before calling
switch (pred.op()) {
case IS_NULL: case NOT_NULL: case EQ: case NOT_EQ: case LT: case LT_EQ:
case GT: case GT_EQ: case IN: case NOT_IN: return true;
default: return false;
} Try / catch
try { return ExpressionUtil.sanitize(pred, now, today); }
catch (UnsupportedOperationException e) { return "<unsupported predicate: " + pred.op() + ">"; } Prevention
- Check pred.op() before sanitizing unbound predicates
- Keep Iceberg versions current for new operations
- Sanitize literals manually for unsupported ops
When it happens
Trigger: Calling ExpressionUtil.sanitize with an UnboundPredicate whose operation is not in the sanitizer's supported set, e.g. STARTS_WITH, COUNT, or a custom operation.
Common situations: Sanitizing expressions containing STARTS_WITH filters on an Iceberg version whose unbound sanitizer predates support for that op; building predicates with newer operations then passing them to older sanitize code.
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
- Cannot sanitize bound predicate type
- AboveMax has no comparator
- BelowMin has no comparator
- BelowMin has no value
- Cannot change the type of BelowMin
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d99afe88fdb5c291.
Report an issue: GitHub.
Appendix: source
Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java:414
// unary predicates don't need to be sanitized
return pred;
case LT:
case LT_EQ:
case GT:
case GT_EQ:
case EQ:
case NOT_EQ:
case STARTS_WITH:
case NOT_STARTS_WITH:
return new UnboundPredicate<>(
pred.op(), pred.term(), (T) sanitize(pred.literal(), now, today));
case IN:
case NOT_IN:
Iterable<T> iter =
() -> pred.literals().stream().map(lit -> (T) sanitize(lit, now, today)).iterator();
return new UnboundPredicate<>(pred.op(), pred.term(), iter);
default:
throw new UnsupportedOperationException(
"Cannot sanitize unsupported predicate type: " + pred.op());
}
}
}
private static class StringSanitizer extends ExpressionVisitors.ExpressionVisitor<String> {
private final long nowMicros;
private final int today;
private StringSanitizer() {
long nowMillis = System.currentTimeMillis();
OffsetDateTime nowDateTime = Instant.ofEpochMilli(nowMillis).atOffset(ZoneOffset.UTC);
this.nowMicros = nowMillis * 1000;
this.today = (int) ChronoUnit.DAYS.between(EPOCH, nowDateTime);
}
@Override
public String alwaysTrue() {View on GitHub (pinned to 86d9c8fc54)