apache/iceberg · error · UnsupportedOperationException

Cannot change the type of BelowMin

Error message

Cannot change the type of BelowMin

What it means

Literal.to(Type) converts a literal to another type; for the BelowMin sentinel there is no value to convert, and its meaning (smaller than everything) is type-independent, so conversion is not defined and throws UnsupportedOperationException. This guards against silently treating the sentinel as a real value.

Source

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

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

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

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

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

  static class BooleanLiteral extends ComparableLiteral<Boolean> {
    BooleanLiteral(Boolean value) {
      super(value);
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Short-circuit: if the literal is Literals.belowMin() (or aboveMax()), skip conversion and let predicate-binding semantics handle it
  2. Validate user-supplied values against the column type before creating a Literal
  3. Rely on UnboundPredicate.bind, which detects sentinels and rewrites operations rather than converting them

Example fix

// before
Literal<?> converted = lit.to(targetType);
// after
if (lit == Literals.belowMin() || lit == Literals.aboveMax()) {
  // handle sentinel at the predicate level; do not convert
} else {
  Literal<?> converted = lit.to(targetType);
}
Defensive patterns

Strategy: type-guard

Validate before calling

Preconditions.checkState(lit != Literals.belowMin() && lit != Literals.aboveMax(), "Cannot convert sentinel literal");

Type guard

static boolean isConvertible(Literal<?> lit) { return lit != Literals.belowMin() && lit != Literals.aboveMax(); }

Try / catch

try { Literal<?> c = lit.to(target); } catch (UnsupportedOperationException e) { /* skip conversion; handle sentinel */ }

Prevention

When it happens

Trigger: Calling to(...) on Literals.belowMin(), typically in generic literal-conversion code, or re-converting a literal that already underflowed during binding.

Common situations: Custom expression visitors that call literal.to(targetType) on every literal in a predicate, hitting the sentinel produced by a previous failed conversion.

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