{"record":{"id":"b43e1c2f01695f85","repo":"apache/iceberg","slug":"cannot-change-the-type-of-belowmin","errorCode":null,"errorMessage":"Cannot change the type of BelowMin","messagePattern":"Cannot change the type of BelowMin","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/Literals.java","lineNumber":214,"sourceCode":"    @Override\n    public String toString() {\n      return \"aboveMax\";\n    }\n  }\n\n  static class BelowMin<T> implements Literal<T> {\n    private static final BelowMin INSTANCE = new BelowMin();\n\n    private BelowMin() {}\n\n    @Override\n    public T value() {\n      throw new UnsupportedOperationException(\"BelowMin has no value\");\n    }\n\n    @Override\n    public <X> Literal<X> to(Type type) {\n      throw new UnsupportedOperationException(\"Cannot change the type of BelowMin\");\n    }\n\n    @Override\n    public Comparator<T> comparator() {\n      throw new UnsupportedOperationException(\"BelowMin has no comparator\");\n    }\n\n    @Override\n    public String toString() {\n      return \"belowMin\";\n    }\n  }\n\n  static class BooleanLiteral extends ComparableLiteral<Boolean> {\n    BooleanLiteral(Boolean value) {\n      super(value);\n    }\n","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/Literals.java#L196-L232","documentation":"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.","triggerScenarios":"Calling to(...) on Literals.belowMin(), typically in generic literal-conversion code, or re-converting a literal that already underflowed during binding.","commonSituations":"Custom expression visitors that call literal.to(targetType) on every literal in a predicate, hitting the sentinel produced by a previous failed conversion.","solutions":["Short-circuit: if the literal is Literals.belowMin() (or aboveMax()), skip conversion and let predicate-binding semantics handle it","Validate user-supplied values against the column type before creating a Literal","Rely on UnboundPredicate.bind, which detects sentinels and rewrites operations rather than converting them"],"exampleFix":"// before\nLiteral<?> converted = lit.to(targetType);\n// after\nif (lit == Literals.belowMin() || lit == Literals.aboveMax()) {\n  // handle sentinel at the predicate level; do not convert\n} else {\n  Literal<?> converted = lit.to(targetType);\n}","handlingStrategy":"type-guard","validationCode":"Preconditions.checkState(lit != Literals.belowMin() && lit != Literals.aboveMax(), \"Cannot convert sentinel literal\");","typeGuard":"static boolean isConvertible(Literal<?> lit) { return lit != Literals.belowMin() && lit != Literals.aboveMax(); }","tryCatchPattern":"try { Literal<?> c = lit.to(target); } catch (UnsupportedOperationException e) { /* skip conversion; handle sentinel */ }","preventionTips":["Skip conversion for sentinel literals in expression visitors","Validate literal type compatibility before calling to()","Use UnboundPredicate.bind rather than manual conversions"],"tags":["expressions","literals","sentinel","type-conversion"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}