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

  1. 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.
  2. Reset/redo the interval: kill the old segments and re-ingest with the desired partitioning.
  3. Check the publish/replace spec so it targets the same root partitions as the segments being replaced.
  4. 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

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


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