apache/iceberg · error · RuntimeException

No other bound is defined.

Error message

No other bound is defined.

What it means

OrcMetrics.truncateIfNeeded truncates ORC string statistics to an Iceberg bound (BELOW/ABOVE) when converting min/max stats to Iceberg literals. The switch over the LowerBound/UpperBound enum has cases for LOWER and UPPER only; any other value falls into the default branch and throws. Since only two bounds exist, this indicates a programming error or a future enum value not yet handled.

Solutions

  1. Upgrade to a current Iceberg version where the bound switch is complete; this path is only reachable with a mismatched or patched build.
  2. Check that you are not mixing iceberg-orc and iceberg-core JARs from different versions on the classpath.
  3. If you maintain a fork, add a case for the new Bound constant (or replace RuntimeException with UnsupportedOperationException for consistency) and a unit test covering both bounds.

Example fix

// before
default:
  throw new RuntimeException("No other bound is defined.");
// after
default:
  throw new UnsupportedOperationException("Unhandled bound: " + bound);
// or add the missing case:
case NEW_BOUND:
  return ...;
Defensive patterns

Strategy: type-guard

Validate before calling

if (bound != Bound.Is.LOWER && bound != Bound.Is.UPPER) { throw new IllegalArgumentException("Unsupported bound: " + bound); }

Type guard

static boolean isSupportedBound(org.apache.iceberg.expressions.Bound<?> b) { return b instanceof org.apache.iceberg.expressions.Bound.Is; }

Try / catch

try { stats = OrcMetrics.fromOrcMin(...); } catch (RuntimeException e) { if (e.getMessage().contains("No other bound")) { skipStats(); } else throw e; }

Prevention

When it happens

Trigger: Calling fromOrcMin or fromOrcMax on OrcMetrics with a CharSequence stat whose bound value is neither Bound.Is BELOW(lower) case nor UPPER case — i.e. a new/unmapped Bound enum constant reaching truncateIfNeeded's default branch.

Common situations: Iceberg version drift where a new Bound constant was added but OrcMetrics was not updated; custom code invoking the private path via reflection or a patched fork passing an unexpected bound.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/9eceeff9ab3ae137. Report an issue: GitHub.

Appendix: source

Thrown at orc/src/main/java/org/apache/iceberg/orc/OrcMetrics.java:372

        || type.typeId() != Type.TypeID.STRING
        || value == null) {
      return value;
    }

    CharSequence charSequence = (CharSequence) value;
    MetricsModes.Truncate truncateMode = (MetricsModes.Truncate) metricsMode;
    int truncateLength = truncateMode.length();

    switch (bound) {
      case UPPER:
        return Optional.ofNullable(
                UnicodeUtil.truncateStringMax(Literal.of(charSequence), truncateLength))
            .map(Literal::value)
            .orElse(charSequence);
      case LOWER:
        return UnicodeUtil.truncateStringMin(Literal.of(charSequence), truncateLength).value();
      default:
        throw new RuntimeException("No other bound is defined.");
    }
  }

  private static Set<Integer> statsColumns(TypeDescription schema) {
    return OrcSchemaVisitor.visit(schema, new StatsColumnsVisitor());
  }

  private static class StatsColumnsVisitor extends OrcSchemaVisitor<Set<Integer>> {
    @Override
    public Set<Integer> record(
        TypeDescription record, List<String> names, List<Set<Integer>> fields) {
      ImmutableSet.Builder<Integer> result = ImmutableSet.builder();
      fields.stream().filter(Objects::nonNull).forEach(result::addAll);
      record.getChildren().stream()
          .map(ORCSchemaUtil::icebergID)
          .filter(Optional::isPresent)
          .map(Optional::get)
          .forEach(result::add);

View on GitHub (pinned to 86d9c8fc54)