apache/iceberg · error · UnsupportedOperationException
Cannot convert to Parquet filter
Error message
Cannot convert to Parquet filter: <pred>
What it means
Thrown when a bound predicate is neither a unary predicate (no literal) nor a literal predicate, so the translator cannot extract a Parquet Literal to build the FilterPredicate. Only unary ops (is-null/not-null) and literal comparisons are convertible; other bound predicate kinds are not.
Solutions
- Restrict pushdown to simple literal/unary predicates on primitive columns; filter the expression tree before calling the translator.
- Rewrite unsupported predicates into supported equivalents at planning time.
- Upgrade Iceberg for broader predicate coverage.
Example fix
// before
pushdown(customNonLiteralPredicate("col")); // non-convertible
// after
pushdown(Expressions.notNull("col")); // unary predicate, convertible Defensive patterns
Strategy: validation
Validate before calling
if (!(pred.isUnaryPredicate() || pred.isLiteralPredicate())) {
// leave for record-level evaluation; do not push down
} Type guard
boolean convertible(BoundPredicate<?> pred) {
return pred.isUnaryPredicate() || pred.isLiteralPredicate();
} Try / catch
try {
FilterPredicate fp = parquetFilters.predicate(pred);
} catch (UnsupportedOperationException e) {
LOG.debug("Skip pushdown: {}", e.getMessage());
return null; // evaluate rows instead
} Prevention
- Push only is-null/not-null and literal comparisons (eq, lt, lte, gt, gte, in, notIn, startsWith).
- Avoid pushing user-supplied custom predicates blindly.
- Update Iceberg when engines introduce new predicate kinds.
When it happens
Trigger: Pushing predicates with complex/transformed terms or non-literal predicate kinds into this translator's predicate(BoundPredicate) method.
Common situations: Custom expression trees; engine versions generating new predicate kinds the translator predates; filters built programmatically with unusual ops.
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 convert non-reference to Parquet filter
- Cannot get NaN value for type
- Failed to check if can be pushed down
- Failed to read required dictionary page for id
- AlwaysFalse is a placeholder only
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9635f879ac59145b.
Report an issue: GitHub.
Appendix: source
Thrown at parquet/src/main/java/org/apache/iceberg/parquet/ParquetFilters.java:127
}
@Override
public <T> FilterPredicate predicate(BoundPredicate<T> pred) {
if (!(pred.term() instanceof BoundReference)) {
throw new UnsupportedOperationException(
"Cannot convert non-reference to Parquet filter: " + pred.term());
}
Operation op = pred.op();
BoundReference<T> ref = (BoundReference<T>) pred.term();
String path = schema.idToAlias(ref.fieldId());
Literal<T> lit;
if (pred.isUnaryPredicate()) {
lit = null;
} else if (pred.isLiteralPredicate()) {
lit = pred.asLiteralPredicate().literal();
} else {
throw new UnsupportedOperationException("Cannot convert to Parquet filter: " + pred);
}
switch (ref.type().typeId()) {
case BOOLEAN:
Operators.BooleanColumn col = FilterApi.booleanColumn(path);
switch (op) {
case EQ:
return FilterApi.eq(col, getParquetPrimitive(lit));
case NOT_EQ:
return FilterApi.notEq(col, getParquetPrimitive(lit));
}
break;
case INTEGER:
case DATE:
return pred(op, FilterApi.intColumn(path), getParquetPrimitive(lit));
case LONG:
case TIME:
case TIMESTAMP:View on GitHub (pinned to 86d9c8fc54)