apache/druid · error · IllegalArgumentException

orderingsToMerge is empty

Error message

orderingsToMerge is empty

What it means

Metadata.mergeOrderings throws IAE when given an empty list of per-segment orderings to merge. Merging sort-order metadata requires at least one input ordering; with none, no merged OrderBy list can be computed.

Solutions

  1. Guard the call site and return a default (e.g. Cursors.ascendingTimeOrder) when the list is empty
  2. Pass a default ordering list for legacy segments instead of an empty list
  3. Only invoke mergeOrderings when at least one segment supplies ordering metadata

Example fix

// before
List<OrderBy> merged = Metadata.mergeOrderings(orderingsToMerge);
// after
List<OrderBy> merged = orderingsToMerge.isEmpty()
    ? Collections.singletonList(OrderBy.ascendingTimeOrder())
    : Metadata.mergeOrderings(orderingsToMerge);
Defensive patterns

Strategy: validation

Validate before calling

if (orderingsToMerge == null || orderingsToMerge.isEmpty()) { return defaultOrdering(); }

Try / catch

try { Metadata.mergeOrderings(list); } catch (IAE e) { if (e.getMessage().contains("orderingsToMerge is empty")) { /* use default time-ordering */ } else throw e; }

Prevention

When it happens

Trigger: Calling Metadata.mergeOrderings(Collections.emptyList()) or mergedOrdering over segments where no segment has ordering metadata (e.g. legacy segments) without defaulting the input lists.

Common situations: Custom tooling reading/merging segment metadata for all-null or legacy segments built before 'ordering' was introduced; compaction code aggregating metadata from empty segment sets.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/ab68a84f2467a561. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/Metadata.java:368

           ", timestampSpec=" + timestampSpec +
           ", queryGranularity=" + queryGranularity +
           ", rollup=" + rollup +
           ", ordering=" + ordering +
           ", projections=" + projections +
           ", clusteredBaseTable=" + clusteredBaseTable +
           '}';
  }

  /**
   * Merge {@link #getOrdering()} from different metadatas.
   *
   * When an input sort order is null, we assume it is {@link Cursors#ascendingTimeOrder()}, as this was the only
   * sort order possible prior to the introduction of the "ordering" field.
   */
  public static List<OrderBy> mergeOrderings(List<List<OrderBy>> orderingsToMerge)
  {
    if (orderingsToMerge.isEmpty()) {
      throw new IAE("orderingsToMerge is empty");
    }

    final List<OrderBy> mergedOrdering = new ArrayList<>();

    while (true) {
      final int position = mergedOrdering.size();
      OrderBy orderBy = null;

      // Iterate through each sort order, check that the columns at "position" are all the same. If not, return
      // the mergedOrdering as-is.
      for (List<OrderBy> ordering : orderingsToMerge) {
        if (ordering == null) {
          // null ordering is treated as [__time].
          ordering = Cursors.ascendingTimeOrder();
        }

        if (position < ordering.size()) {
          if (orderBy == null) {

View on GitHub (pinned to 9b90983fd2)