apache/druid · error · IllegalStateException
Root partition range[%d, %d] of new segments doesn't match t
Error message
Root partition range[%d, %d] of new segments doesn't match to root partition range[%d, %d] of old segments
What it means
SegmentTransactionalInsertAction.checkWithSegmentLock() validates that when new segments replace old segments for an interval, the new segments' root partition range exactly matches the old ones'. Root partition ids define top-level chunk boundaries in the segment partitioning lineage; a mismatch means the publish would change the core partition layout of existing data, which core partition sets forbid. Druid throws this ISE to protect lineage consistency.
Source
Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentTransactionalInsertAction.java:293
oldSegmentsMap.values().forEach(TaskLockHelper::verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull);
newSegmentsMap.values().forEach(TaskLockHelper::verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull);
oldSegmentsMap.forEach((interval, oldSegmentsPerInterval) -> {
final List<DataSegment> newSegmentsPerInterval = Preconditions.checkNotNull(
newSegmentsMap.get(interval),
"segments of interval[%s]",
interval
);
// These lists are already sorted in groupSegmentsByIntervalAndSort().
final int oldStartRootPartitionId = oldSegmentsPerInterval.get(0).getStartRootPartitionId();
final int oldEndRootPartitionId = oldSegmentsPerInterval.get(oldSegmentsPerInterval.size() - 1)
.getEndRootPartitionId();
final int newStartRootPartitionId = newSegmentsPerInterval.get(0).getStartRootPartitionId();
final int newEndRootPartitionId = newSegmentsPerInterval.get(newSegmentsPerInterval.size() - 1)
.getEndRootPartitionId();
if (oldStartRootPartitionId != newStartRootPartitionId || oldEndRootPartitionId != newEndRootPartitionId) {
throw new ISE(
"Root partition range[%d, %d] of new segments doesn't match to root partition range[%d, %d] of old segments",
newStartRootPartitionId,
newEndRootPartitionId,
oldStartRootPartitionId,
oldEndRootPartitionId
);
}
newSegmentsPerInterval
.forEach(eachNewSegment -> oldSegmentsPerInterval
.forEach(eachOldSegment -> {
if (eachNewSegment.getMinorVersion() <= eachOldSegment.getMinorVersion()) {
throw new ISE(
"New segment[%s] have a smaller minor version than old segment[%s]",
eachNewSegment,
eachOldSegment
);
}View on GitHub (pinned to 9b90983fd2)
Solutions
- Align the new taskspec's partitioning (num SHARDS/root partitions) with the existing segments for that interval, or use a higher minor version replace that covers the full root partition range.
- Reset/redo the interval: kill the old segments and re-ingest with the desired partitioning.
- Check the publish/replace spec so it targets the same root partitions as the segments being replaced.
- Verify you are not replaying a stale task payload referencing old partitioning.
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
int oldStart = oldSegments.get(0).getStartRootPartitionId();
int oldEnd = oldSegments.get(oldSegments.size()-1).getEndRootPartitionId();
int newStart = newSegments.get(0).getStartRootPartitionId();
int newEnd = newSegments.get(newSegments.size()-1).getEndRootPartitionId();
if (oldStart != newStart || oldEnd != newEnd) {
throw new IllegalStateException("root partition range mismatch: fix partitioning spec or kill+re-ingest");
} Try / catch
try { result = action.perform(task, toolbox); } catch (ISE e) { if (e.getMessage().contains("Root partition range")) { /* align partitioning or re-ingest interval */ } else throw e; } Prevention
- Keep partitioning configuration stable for a given interval across retries.
- Use replace/compaction with matching root partitions, or full-coverage replace with a bumped minor version.
- Kill and re-ingest when changing partition layout for existing intervals.
- Diff old vs new segment partition info before publishing.
When it happens
Trigger: Publishing append/replace segments whose start/end root partition ids differ from the existing segments for the same interval — e.g. an overwrite with different partitioning than the original ingestion, or a task retry with a stale segment set.
Common situations: Re-running compaction with a different partitioning config against an interval already compacted differently; supervisor tasks restarted after the segment layout changed; hand-edited or stale taskspec reusing old segment ids.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- New segment[%s] have a smaller minor version than old segmen
- partitionDimensions must be specified
- forceGuaranteedRollup is incompatible with partitionsSpec: %
- Transaction failure publishing segments for sequence [%s]
- Emit called unexpectedly before service start
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/2e387c064fd26a8a.
Report an issue: GitHub.