apache/iceberg · error · UnsupportedOperationException

Cannot unbind unsupported term

Error message

Cannot unbind unsupported term: ${term}

What it means

ExpressionUtil.unbind(BoundTerm) can only convert BoundTransform and BoundReference back to unbound terms. Any other BoundTerm implementation cannot be reversed and triggers this UnsupportedOperationException.

Solutions

  1. Inspect the bound term class; if it is a BoundAggregate or other unsupported type, extract the reference via term.ref()/term.term() and unbind that
  2. Upgrade Iceberg to a version that handles the term type
  3. Rewrite the logic to use Expressions.transform(ref.name(), transform) or Expressions.ref(name) manually for the known type
  4. Avoid unbinding terms of unsupported kinds; keep the unbound form before binding if you need it later

Example fix

// before
UnboundTerm<?> unbound = ExpressionUtil.unbind(boundAggregate);
// after
UnboundTerm<?> unbound = boundAggregate instanceof BoundReference
    ? Expressions.ref(((BoundReference<?>) boundAggregate).name())
    : ExpressionUtil.unbind((BoundTerm<?>) boundAggregate);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(term instanceof BoundTransform) && !(term instanceof BoundReference)) {
  throw new IllegalArgumentException("Cannot unbind term type: " + term.getClass());
}

Type guard

boolean isUnbindable(BoundTerm<?> t) {
  return t instanceof BoundTransform || t instanceof BoundReference;
}

Try / catch

try { return ExpressionUtil.unbind(boundTerm); }
catch (UnsupportedOperationException e) { LOGGER.warn("unbind unsupported for {}", boundTerm.getClass()); return null; }

Prevention

When it happens

Trigger: Calling ExpressionUtil.unbind(BoundTerm) (directly or via unbind(Term)) with a bound term that is not a BoundTransform or BoundReference, e.g. a custom BoundTerm implementation.

Common situations: Custom aggregate or metric term implementations; newer Iceberg term types appearing in bound expressions while running an older client; passing bound aggregates through unbind during predicate rewriting.

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/26b281e8f9cffe3b. Report an issue: GitHub.

Appendix: source

Thrown at api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java:259

          + ")";
    } else if (term instanceof NamedReference) {
      return ((NamedReference<?>) term).name();
    } else if (term instanceof BoundReference) {
      return ((BoundReference<?>) term).name();
    } else {
      throw new UnsupportedOperationException("Unsupported term: " + term);
    }
  }

  public static <T> UnboundTerm<T> unbind(BoundTerm<T> term) {
    if (term instanceof BoundTransform) {
      BoundTransform<?, T> bound = (BoundTransform<?, T>) term;
      return Expressions.transform(bound.ref().name(), bound.transform());
    } else if (term instanceof BoundReference) {
      return Expressions.ref(((BoundReference<T>) term).name());
    }

    throw new UnsupportedOperationException("Cannot unbind unsupported term: " + term);
  }

  @SuppressWarnings("unchecked")
  public static <T> UnboundTerm<T> unbind(Term term) {
    if (term instanceof UnboundTerm) {
      return (UnboundTerm<T>) term;
    } else if (term instanceof BoundTerm) {
      return unbind((BoundTerm<T>) term);
    }

    throw new UnsupportedOperationException("Cannot unbind unsupported term: " + term);
  }

  private static class RetainPredicatesByFieldIdVisitor
      extends ExpressionVisitors.ExpressionVisitor<Expression> {
    private final Schema schema;
    private final boolean caseSensitive;
    private final Set<Integer> retainFieldIds;

View on GitHub (pinned to 86d9c8fc54)