apache/druid · error · IllegalArgumentException

Adjacent intervals are not sorted

Error message

Adjacent intervals are not sorted [%s,%s]

What it means

JodaUtils.mergeIntervals requires its input intervals to be sorted in ascending order; verifyAscendingSortOrder throws this IAE when a previous interval is strictly after (isAfter) the current one. The merging algorithm relies on sortedness to detect abutting/overlapping intervals in a single pass, so unsorted input would produce wrong results and is rejected.

Solutions

  1. Sort before merging: intervals.sort(Interval::compareTo) or intervals.stream().sorted().collect(...)
  2. If using Java, build a TreeSet<Interval> from the input to get sorted, deduplicated intervals
  3. Verify the upstream producer emits chronologically ordered intervals

Example fix

// before
JodaUtils.mergeIntervals(Arrays.asList(later, earlier)); // IAE
// after
List<Interval> sorted = intervals.stream().sorted().collect(Collectors.toList());
JodaUtils.mergeIntervals(sorted);
Defensive patterns

Strategy: validation

Validate before calling

List<Interval> sorted = intervals.stream().sorted().collect(Collectors.toList());
JodaUtils.mergeIntervals(sorted);

Type guard

static boolean isSorted(List<Interval> list) {
  for (int i = 1; i < list.size(); i++) {
    if (list.get(i - 1).isAfter(list.get(i))) return false;
  }
  return true;
}

Try / catch

try {
  return JodaUtils.mergeIntervals(intervals);
} catch (IllegalArgumentException e) {
  List<Interval> sorted = new ArrayList<>(intervals);
  sorted.sort(Comparator.naturalOrder());
  return JodaUtils.mergeIntervals(sorted);
}

Prevention

When it happens

Trigger: Calling mergeIntervals with a list like [2023-01-02/2023-01-03, 2023-01-01/2023-01-02] where an earlier interval follows a later one; any partially sorted or reversed interval collection.

Common situations: Intervals accumulated from unordered sources (segment lists from different workers, map iteration order, user-specified rules) and passed directly without sorting.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/java/util/common/JodaUtils.java:163

            DateTime currEnd = currInterval.getEnd();
            currInterval = new Interval(
                currInterval.getStart(),
                nextEnd.isAfter(currEnd) ? nextEnd : currEnd
            );
            peekingIterator.next();
          } else {
            break;
          }
        }
        return currInterval;
      }
    };
  }

  private static void verifyAscendingSortOrder(Interval previous, Interval current)
  {
    if (previous != null && previous.isAfter(current)) {
      throw new IAE("Adjacent intervals are not sorted [%s,%s]", previous, current);
    }
  }

  public static Interval umbrellaInterval(Iterable<Interval> intervals)
  {
    boolean emptyIntervals = true;
    DateTimeComparator dateTimeComp = DateTimeComparator.getInstance();
    DateTime minStart = new DateTime(Long.MAX_VALUE, ISOChronology.getInstanceUTC());
    DateTime maxEnd = new DateTime(Long.MIN_VALUE, ISOChronology.getInstanceUTC());

    for (Interval interval : intervals) {
      emptyIntervals = false;
      minStart = Collections.min(ImmutableList.of(minStart, interval.getStart()), dateTimeComp);
      maxEnd = Collections.max(ImmutableList.of(maxEnd, interval.getEnd()), dateTimeComp);
    }

    if (emptyIntervals) {
      throw new IllegalArgumentException("Empty list of intervals");

View on GitHub (pinned to 9b90983fd2)