{"record":{"id":"e60e6f1022d8796e","repo":"apache/iceberg","slug":"belowmin-has-no-comparator","errorCode":null,"errorMessage":"BelowMin has no comparator","messagePattern":"BelowMin has no comparator","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/expressions/Literals.java","lineNumber":219,"sourceCode":"\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\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> Literal<T> to(Type type) {\n      if (type.typeId() == Type.TypeID.BOOLEAN) {\n        return (Literal<T>) this;","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/expressions/Literals.java#L201-L237","documentation":"Same rationale as AboveMax: the BelowMin sentinel carries no value, so no Comparator can be produced for it. Ordering of the sentinel is defined implicitly by predicate-binding semantics (anything is greater than belowMin), not by a comparator object.","triggerScenarios":"Calling comparator() on Literals.belowMin(), e.g. in generic expression evaluation code that obtains a comparator for every literal or bound term.","commonSituations":"Custom predicate evaluators or metrics-based filter pushdown that uniformly request comparators and trip over sentinel literals produced by conversion overflow/underflow.","solutions":["Exclude belowMin/aboveMax sentinels before requesting a comparator and resolve comparisons via operation semantics","Inspect the predicate after binding; bound predicates from sentinels are typically rewritten to always-true/false","Validate literal ranges against the column type up front so sentinels are never produced"],"exampleFix":"// before\nComparator<T> cmp = lit.comparator();\n// after\nif (lit == Literals.belowMin()) {\n  // belowMin compares less than everything; no comparator needed\n} else {\n  Comparator<T> cmp = lit.comparator();\n}","handlingStrategy":"type-guard","validationCode":"if (lit == Literals.belowMin() || lit == Literals.aboveMax()) { throw new IllegalArgumentException(\"Sentinel literal has no comparator\"); }","typeGuard":"static boolean hasComparator(Literal<?> lit) { return lit != Literals.belowMin() && lit != Literals.aboveMax(); }","tryCatchPattern":"try { Comparator<?> cmp = lit.comparator(); } catch (UnsupportedOperationException e) { /* belowMin is less than everything; decide via operation */ }","preventionTips":["Exclude sentinels before requesting comparators in evaluators","Rely on bound-predicate evaluation which encodes sentinel ordering","Add regression tests with literals that underflow the column type"],"tags":["expressions","literals","sentinel","unsupported"],"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"}