apache/iceberg · error · UnsupportedOperationException

Unsupported term: ${term}

Error message

Unsupported term: ${term}

What it means

ExpressionUtil's term-to-string helper (used by describe/sanitize/describe quoting) only knows NamedReference and BoundReference term types. Any other Term implementation passed to it hits this fallback UnsupportedOperationException. It signals an unhandled term variant in code that renders terms as strings.

Source

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

  }

  public static String describe(Term term) {
    if (term instanceof UnboundTransform) {
      return ((UnboundTransform<?, ?>) term).transform()
          + "("
          + describe(((UnboundTransform<?, ?>) term).ref())
          + ")";
    } else if (term instanceof BoundTransform) {
      return ((BoundTransform<?, ?>) term).transform()
          + "("
          + describe(((BoundTransform<?, ?>) term).ref())
          + ")";
    } 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;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check the actual runtime type of the term before calling describe (NamedReference/BoundReference only)
  2. Upgrade Iceberg if using a new term type like UnboundTransform that a newer version handles
  3. Use ExpressionUtil.describe(Expression) on the full expression instead of describing terms directly
  4. If a custom Term was implemented, convert it to a supported reference or handle it before calling describe

Example fix

// before
String desc = ExpressionUtil.describe(myUnboundTransformTerm);
// after
Term ref = term instanceof UnboundTransform ? ((UnboundTransform<?, ?>) term).ref() : term;
String desc = ExpressionUtil.describe(ref);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(term instanceof NamedReference) && !(term instanceof BoundReference)) {
  throw new IllegalArgumentException("describe() supports only named/bound references, got: " + term.getClass());
}

Type guard

boolean isDescribableTerm(Term t) {
  return t instanceof NamedReference || t instanceof BoundReference;
}

Try / catch

try { return ExpressionUtil.describe(term); }
catch (UnsupportedOperationException e) { return term != null ? term.toString() : "<unknown term>"; }

Prevention

When it happens

Trigger: Calling ExpressionUtil.describe (or the sanitizing visitors that call it) with a Term that is neither NamedReference nor BoundReference, e.g. an UnboundTransform or a custom Term implementation.

Common situations: Custom expression extensions or new term types added in newer Iceberg versions but not yet handled by the describe helper; passing an UnboundTransform term from a transform expression into ExpressionUtil.describe; reflection-built terms from other modules.

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