apache/iceberg · error · UnsupportedOperationException

AboveMax has no comparator

Error message

AboveMax has no comparator

What it means

AboveMax is a sentinel literal representing values larger than any representable value of a column's type (e.g. from literal conversion overflow). It exists only so predicate binding can detect 'value too large' and rewrite comparisons (e.g. LT becomes always-false). It carries no actual value, so obtaining a Comparator for it is meaningless and the library throws UnsupportedOperationException.

Source

Thrown at api/src/main/java/org/apache/iceberg/expressions/Literals.java:193

  static class AboveMax<T> implements Literal<T> {
    private static final AboveMax INSTANCE = new AboveMax();

    private AboveMax() {}

    @Override
    public T value() {
      throw new UnsupportedOperationException("AboveMax has no value");
    }

    @Override
    public <X> Literal<X> to(Type type) {
      throw new UnsupportedOperationException("Cannot change the type of AboveMax");
    }

    @Override
    public Comparator<T> comparator() {
      throw new UnsupportedOperationException("AboveMax has no comparator");
    }

    @Override
    public String toString() {
      return "aboveMax";
    }
  }

  static class BelowMin<T> implements Literal<T> {
    private static final BelowMin INSTANCE = new BelowMin();

    private BelowMin() {}

    @Override
    public T value() {
      throw new UnsupportedOperationException("BelowMin has no value");
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Exclude Literals.aboveMax() and Literals.belowMax() sentinels before calling comparator(); handle them with dedicated comparison logic
  2. Check the literal class/sentinel identity first and branch to sentinel-aware logic
  3. Use the bound expression API (Expressions/Binder) instead of manually comparing sentinel literals

Example fix

// before
Comparator<T> cmp = lit.comparator();
// after
if (lit == Literals.aboveMax() || lit == Literals.belowMin()) {
  // handle sentinel: comparison result is decided by the operation, not a comparator
} else {
  Comparator<T> cmp = lit.comparator();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (lit == Literals.aboveMax() || lit == Literals.belowMin()) { throw new IllegalArgumentException("Sentinel literal has no comparator"); }

Type guard

static boolean isSentinel(Literal<?> lit) { return lit == Literals.aboveMax() || lit == Literals.belowMin(); }

Try / catch

try { Comparator<?> cmp = lit.comparator(); } catch (UnsupportedOperationException e) { /* sentinel path: resolve via operation semantics */ }

Prevention

When it happens

Trigger: Calling comparator() on the object returned by Literals.aboveMax(), typically after literal().to(type) returned aboveMax during predicate binding, or explicitly calling Literals.aboveMax().comparator() in custom expression code.

Common situations: Custom scan-planning or expression-rewriting code that generically calls literal.comparator() on every literal without excluding the aboveMax/belowMin sentinels.

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