{"record":{"id":"26b281e8f9cffe3b","repo":"apache/iceberg","slug":"cannot-unbind-unsupported-term-term","errorCode":null,"errorMessage":"Cannot unbind unsupported term: ${term}","messagePattern":"Cannot unbind unsupported term: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java","lineNumber":259,"sourceCode":"          + \")\";\n    } else if (term instanceof NamedReference) {\n      return ((NamedReference<?>) term).name();\n    } else if (term instanceof BoundReference) {\n      return ((BoundReference<?>) term).name();\n    } else {\n      throw new UnsupportedOperationException(\"Unsupported term: \" + term);\n    }\n  }\n\n  public static <T> UnboundTerm<T> unbind(BoundTerm<T> term) {\n    if (term instanceof BoundTransform) {\n      BoundTransform<?, T> bound = (BoundTransform<?, T>) term;\n      return Expressions.transform(bound.ref().name(), bound.transform());\n    } else if (term instanceof BoundReference) {\n      return Expressions.ref(((BoundReference<T>) term).name());\n    }\n\n    throw new UnsupportedOperationException(\"Cannot unbind unsupported term: \" + term);\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  public static <T> UnboundTerm<T> unbind(Term term) {\n    if (term instanceof UnboundTerm) {\n      return (UnboundTerm<T>) term;\n    } else if (term instanceof BoundTerm) {\n      return unbind((BoundTerm<T>) term);\n    }\n\n    throw new UnsupportedOperationException(\"Cannot unbind unsupported term: \" + term);\n  }\n\n  private static class RetainPredicatesByFieldIdVisitor\n      extends ExpressionVisitors.ExpressionVisitor<Expression> {\n    private final Schema schema;\n    private final boolean caseSensitive;\n    private final Set<Integer> retainFieldIds;","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java#L241-L277","documentation":"ExpressionUtil.unbind(BoundTerm) can only convert BoundTransform and BoundReference back to unbound terms. Any other BoundTerm implementation cannot be reversed and triggers this UnsupportedOperationException.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Upgrade Iceberg to a version that handles the term type","Rewrite the logic to use Expressions.transform(ref.name(), transform) or Expressions.ref(name) manually for the known type","Avoid unbinding terms of unsupported kinds; keep the unbound form before binding if you need it later"],"exampleFix":"// before\nUnboundTerm<?> unbound = ExpressionUtil.unbind(boundAggregate);\n// after\nUnboundTerm<?> unbound = boundAggregate instanceof BoundReference\n    ? Expressions.ref(((BoundReference<?>) boundAggregate).name())\n    : ExpressionUtil.unbind((BoundTerm<?>) boundAggregate);","handlingStrategy":"type-guard","validationCode":"if (!(term instanceof BoundTransform) && !(term instanceof BoundReference)) {\n  throw new IllegalArgumentException(\"Cannot unbind term type: \" + term.getClass());\n}","typeGuard":"boolean isUnbindable(BoundTerm<?> t) {\n  return t instanceof BoundTransform || t instanceof BoundReference;\n}","tryCatchPattern":"try { return ExpressionUtil.unbind(boundTerm); }\ncatch (UnsupportedOperationException e) { LOGGER.warn(\"unbind unsupported for {}\", boundTerm.getClass()); return null; }","preventionTips":["Retain the original unbound term instead of unbinding later","Only unbind BoundTransform/BoundReference instances","Pin client and server Iceberg versions to avoid term-type drift"],"tags":["expressions","unbind"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}