apache/druid · error · ISE
segment[%s] and segment[%s] have the same rootPartitionRange
Error message
segment[%s] and segment[%s] have the same rootPartitionRange, but different minorVersion or atomicUpdateGroupSize
What it means
Thrown by verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull when two consecutive sorted segments share the exact same rootPartition range (same startRootPartitionId and endRootPartitionId) but differ in minorVersion or atomicUpdateGroupSize. Segments occupying the same root-partition slot must belong to one complete atomic-update group (same minor version and group size) so the overwrite can safely replace them together; disagreement indicates a corrupt or mixed shadowing state.
Source
Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/TaskLockHelper.java:280
if (sortedSegments.isEmpty()) {
return;
}
Preconditions.checkArgument(
sortedSegments.stream().allMatch(segment -> segment.getInterval().equals(sortedSegments.get(0).getInterval()))
);
short atomicUpdateGroupSize = 1;
// sanity check
for (int i = 0; i < sortedSegments.size() - 1; i++) {
final DataSegment curSegment = sortedSegments.get(i);
final DataSegment nextSegment = sortedSegments.get(i + 1);
if (curSegment.getStartRootPartitionId() == nextSegment.getStartRootPartitionId()
&& curSegment.getEndRootPartitionId() == nextSegment.getEndRootPartitionId()) {
// Input segments should have the same or consecutive rootPartition range
if (curSegment.getMinorVersion() != nextSegment.getMinorVersion()
|| curSegment.getAtomicUpdateGroupSize() != nextSegment.getAtomicUpdateGroupSize()) {
throw new ISE(
"segment[%s] and segment[%s] have the same rootPartitionRange, but different minorVersion or atomicUpdateGroupSize",
curSegment,
nextSegment
);
}
atomicUpdateGroupSize++;
} else {
if (curSegment.getEndRootPartitionId() != nextSegment.getStartRootPartitionId()) {
throw new ISE(
"Can't compact segments of non-consecutive rootPartition range. Missing partitionIds between [%s] and [%s]",
curSegment.getEndRootPartitionId(),
nextSegment.getStartRootPartitionId()
);
}
if (atomicUpdateGroupSize != curSegment.getAtomicUpdateGroupSize()) {
throw new ISE(
"All atomicUpdateGroup must be compacted together. Expected size[%s] but current size[%s]",
curSegment.getAtomicUpdateGroupSize(),View on GitHub (pinned to 9b90983fd2)
Solutions
- Include ALL segments of the affected rootPartitionRange (the full atomicUpdateGroup) in the task's input segment list.
- Inspect the segments (segment metadata query or segments table) sharing the rootPartitionRange and remove/overwrite stale ones with mismatched minorVersion via a full replace.
- Re-run compaction over the whole interval so all segments are rewritten into a single consistent generation.
- Check for concurrently running tasks over the same interval and cancel or wait for them before retrying.
Example fix
// before: partial input, one segment of an atomicUpdateGroup missing List<DataSegment> input = segments.stream().filter(s -> s.getVersion().equals(targetVersion)).collect(toList()); verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(input); // ISE // after: take all segments in the interval so each group is complete List<DataSegment> input = segmentCache.getUsedSegmentsForInterval(ds, interval); verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(input);
Defensive patterns
Strategy: validation
Validate before calling
// Java: group segments by rootPartitionRange and check consistent minorVersion/atomicUpdateGroupSize
Map<List<Integer>, List<DataSegment>> byRange = segments.stream()
.collect(Collectors.groupingBy(s -> Arrays.asList(s.getStartRootPartitionId(), s.getEndRootPartitionId())));
for (List<DataSegment> group : byRange.values()) {
long minorVers = group.stream().map(DataSegment::getMinorVersion).distinct().count();
long sizes = group.stream().map(DataSegment::getAtomicUpdateGroupSize).distinct().count();
if (minorVers != 1 || sizes != 1) throw new IllegalStateException("Mixed generation within a rootPartitionRange");
} Try / catch
try {
TaskLockHelper.verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(sorted);
} catch (IllegalStateException e) {
if (e.getMessage().contains("same rootPartitionRange")) {
// re-run full replace of the interval to rebuild a consistent generation
} else { throw e; }
} Prevention
- Never rewrite only part of an atomicUpdateGroup; compact whole intervals.
- Avoid running concurrent replace/append tasks over the same interval.
- Keep tuning partitioning (rows per segment) stable across partial compactions.
When it happens
Trigger: verifyAndLockExistingSegments -> tryLockSegments -> verifyAndFindRootPartitionRangeAndMinorVersion with segments in one interval where two segments have identical rootPartitionRange but were written by different replace/append generations (different minorVersion) or with different maxRowsInMemory/partitioning, yielding different atomicUpdateGroupSize.
Common situations: Overlapping partial compactions that rewrote only part of an atomicUpdateGroup; concurrent replace tasks that published segments at different minorVersions for the same partition slot; corrupted/metadata-rebuilt segment lists; changing tuning partitioning (rows-per-partition) between partial compaction runs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Can't compact segments of non-consecutive rootPartition rang
- All atomicUpdateGroup must be compacted together. Expected s
- Interval[%s] is empty, must specify a nonempty interval
- Conflicting segment granularities found %s(segmentGranularit
- Unknown tuningConfig type: [%s], Must be in [%s, %s, %s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/824e5bbfa1f6bf71.
Report an issue: GitHub.