apache/iceberg · error · UnsupportedOperationException
Unsupported predicate operation
Error message
Unsupported predicate operation: <op>
What it means
The private pred() helper maps a bound predicate operation (EQ, NOT_EQ, GT, GT_EQ, LT, LT_EQ) to the corresponding Parquet FilterApi call. Any other operation reaching the default branch is rejected with this UnsupportedOperationException. It is a guard against operations the Parquet column-index filter API cannot express.
Solutions
- Use only comparison operators (==, !=, <, <=, >, >=) in expressions intended for Parquet pushdown
- Rewrite IN as an OR of equalities, or handle the predicate client-side instead of pushdown
- Catch UnsupportedOperationException and skip pushdown for that filter
Example fix
// before
Expression e = Expressions.startsWith("name", "A");
FilterPredicate p = ParquetFilters.predicate(binder.bind(schema, e)); // throws
// after
Expression e = Expressions.equal("name", "Alice");
FilterPredicate p = ParquetFilters.predicate(binder.bind(schema, e)); Defensive patterns
Strategy: validation
Validate before calling
switch (pred.op()) {
case EQ: case NOT_EQ: case GT: case GT_EQ: case LT: case LT_EQ: break;
default: throw new IllegalArgumentException("Not Parquet-pushdownable: " + pred.op());
} Try / catch
try {
FilterPredicate p = ParquetFilters.predicate(bound);
} catch (UnsupportedOperationException e) {
logger.warn("Skipping pushdown: {}", e.getMessage());
} Prevention
- Use only =, !=, <, <=, >, >= for Parquet pushdown
- Handle IN/startsWith/null checks outside pushdown
When it happens
Trigger: Calling ParquetFilters.predicate() with a bound predicate whose operation is not one of EQ, NOT_EQ, GT, GT_EQ, LT, LT_EQ — e.g. STARTS_WITH, IN, or IS_NULL bound predicates that reach the pred() helper.
Common situations: Pushing down string startsWith filters, IN-list filters, or null checks on a Parquet scan; using expression types from a newer Iceberg version with an older converter.
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
- AlwaysFalse is a placeholder only
- AlwaysTrue is a placeholder only
- Batch reading is not supported in non-vectorized reader
- doesn't implement setPageSource(PageReadStore)
- doesn't implement setRowGroupInfo(PageReadStore…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/ead618cfbd8d9e4f.
Report an issue: GitHub.
Appendix: source
Thrown at parquet/src/main/java/org/apache/iceberg/parquet/ParquetFilters.java:214
} else if (col.getColumnType().equals(Float.class)) {
return FilterApi.notEq(col, (C) (Float) Float.NaN);
} else {
return AlwaysTrue.INSTANCE;
}
case EQ:
return FilterApi.eq(col, value);
case NOT_EQ:
return FilterApi.notEq(col, value);
case GT:
return FilterApi.gt(col, value);
case GT_EQ:
return FilterApi.gtEq(col, value);
case LT:
return FilterApi.lt(col, value);
case LT_EQ:
return FilterApi.ltEq(col, value);
default:
throw new UnsupportedOperationException("Unsupported predicate operation: " + op);
}
}
@SuppressWarnings("unchecked")
private static <C extends Comparable<C>> C getParquetPrimitive(Literal<?> lit) {
if (lit == null) {
return null;
}
// TODO: this needs to convert to handle BigDecimal and UUID
Object value = lit.value();
if (value instanceof Number) {
return (C) lit.value();
} else if (value instanceof CharSequence) {
return (C) Binary.fromString(value.toString());
} else if (value instanceof ByteBuffer) {
return (C) Binary.fromReusedByteBuffer((ByteBuffer) value);
}View on GitHub (pinned to 86d9c8fc54)