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
- Sort before merging: intervals.sort(Interval::compareTo) or intervals.stream().sorted().collect(...)
- If using Java, build a TreeSet<Interval> from the input to get sorted, deduplicated intervals
- 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
- Always sort interval lists before merging — the utility requires ascending order
- Collect intervals into a TreeSet<Interval> to guarantee ordering at construction
- Never assume upstream producers emit chronologically ordered intervals
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
- Element of intervals is null
- Empty list of intervals
- Cannot add merged batches for level
- Cannot filter datasource
- Cannot set mergers for final level more than once
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)