apache/iceberg · error · UnsupportedOperationException

Cannot convert non-reference to Parquet filter

Error message

Cannot convert non-reference to Parquet filter: <term>

What it means

The Parquet filter translator converts bound Iceberg predicates into parquet-mr FilterPredicates for pushdown. Parquet can only evaluate predicates on direct column references; if a bound predicate's term is not a BoundReference (e.g. a BoundTransform or other composite term), it cannot be pushed down and this UnsupportedOperationException is thrown.

Solutions

  1. Rewrite the filter to reference the raw column and apply transforms after reading, or pre-filter unsupported predicates at planning time.
  2. Only pass predicates whose terms are plain references to predicate()/ParquetFilters.
  3. Upgrade Iceberg — newer code paths remove unsupported predicates instead of throwing.

Example fix

// before
filter = Expressions.equal(Expressions.bucket("id", 16), 5); // pushed straight down
// after
filter = Expressions.in("id", <resolved bucket member values>); // push on the reference, transform applied at planning time
Defensive patterns

Strategy: validation

Validate before calling

// only push down predicates on plain column references
if (pred instanceof BoundPredicate
    && !(((BoundPredicate<?>) pred).term() instanceof BoundReference)) {
  // do not push this predicate down; keep it for post-scan evaluation
}

Type guard

boolean isPushable(BoundPredicate<?> pred) {
  return pred.term() instanceof BoundReference;
}

Try / catch

try {
  FilterPredicate fp = parquetFilters.predicate(pred);
} catch (UnsupportedOperationException e) {
  LOG.debug("Predicate not pushable: {}", e.getMessage());
  unpushed.add(pred);
}

Prevention

When it happens

Trigger: Evaluating an expression containing transform terms (e.g. bucket(...), truncate(...), year(ts)) against Parquet with this translator when the term binds to something other than a plain column reference.

Common situations: Queries with partition-transform expressions in filters combined with strict pushdown paths; custom expressions using BoundTransform; engine integration pushing whole bound expression trees into ParquetFilters.

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/363afb672efc92ab. Report an issue: GitHub.

Appendix: source

Thrown at parquet/src/main/java/org/apache/iceberg/parquet/ParquetFilters.java:114

    public FilterPredicate or(FilterPredicate left, FilterPredicate right) {
      if (left == AlwaysTrue.INSTANCE || right == AlwaysTrue.INSTANCE) {
        return AlwaysTrue.INSTANCE;
      } else if (left == AlwaysFalse.INSTANCE) {
        return right;
      } else if (right == AlwaysFalse.INSTANCE) {
        return left;
      }
      return FilterApi.or(left, right);
    }

    protected Expression bind(UnboundPredicate<?> pred) {
      return pred.bind(schema.asStruct(), caseSensitive);
    }

    @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);

View on GitHub (pinned to 86d9c8fc54)