{"record":{"id":"824e5bbfa1f6bf71","repo":"apache/druid","slug":"segment-s-and-segment-s-have-the-same-rootpart","errorCode":null,"errorMessage":"segment[%s] and segment[%s] have the same rootPartitionRange, but different minorVersion or atomicUpdateGroupSize","messagePattern":"segment\\[(.+?)\\] and segment\\[(.+?)\\] have the same rootPartitionRange, but different minorVersion or atomicUpdateGroupSize","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/TaskLockHelper.java","lineNumber":280,"sourceCode":"    if (sortedSegments.isEmpty()) {\n      return;\n    }\n\n    Preconditions.checkArgument(\n        sortedSegments.stream().allMatch(segment -> segment.getInterval().equals(sortedSegments.get(0).getInterval()))\n    );\n\n    short atomicUpdateGroupSize = 1;\n    // sanity check\n    for (int i = 0; i < sortedSegments.size() - 1; i++) {\n      final DataSegment curSegment = sortedSegments.get(i);\n      final DataSegment nextSegment = sortedSegments.get(i + 1);\n      if (curSegment.getStartRootPartitionId() == nextSegment.getStartRootPartitionId()\n          && curSegment.getEndRootPartitionId() == nextSegment.getEndRootPartitionId()) {\n        // Input segments should have the same or consecutive rootPartition range\n        if (curSegment.getMinorVersion() != nextSegment.getMinorVersion()\n            || curSegment.getAtomicUpdateGroupSize() != nextSegment.getAtomicUpdateGroupSize()) {\n          throw new ISE(\n              \"segment[%s] and segment[%s] have the same rootPartitionRange, but different minorVersion or atomicUpdateGroupSize\",\n              curSegment,\n              nextSegment\n          );\n        }\n        atomicUpdateGroupSize++;\n      } else {\n        if (curSegment.getEndRootPartitionId() != nextSegment.getStartRootPartitionId()) {\n          throw new ISE(\n              \"Can't compact segments of non-consecutive rootPartition range. Missing partitionIds between [%s] and [%s]\",\n              curSegment.getEndRootPartitionId(),\n              nextSegment.getStartRootPartitionId()\n          );\n        }\n        if (atomicUpdateGroupSize != curSegment.getAtomicUpdateGroupSize()) {\n          throw new ISE(\n              \"All atomicUpdateGroup must be compacted together. Expected size[%s] but current size[%s]\",\n              curSegment.getAtomicUpdateGroupSize(),","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/TaskLockHelper.java#L262-L298","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: partial input, one segment of an atomicUpdateGroup missing\nList<DataSegment> input = segments.stream().filter(s -> s.getVersion().equals(targetVersion)).collect(toList());\nverifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(input); // ISE\n\n// after: take all segments in the interval so each group is complete\nList<DataSegment> input = segmentCache.getUsedSegmentsForInterval(ds, interval);\nverifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(input);","handlingStrategy":"validation","validationCode":"// Java: group segments by rootPartitionRange and check consistent minorVersion/atomicUpdateGroupSize\nMap<List<Integer>, List<DataSegment>> byRange = segments.stream()\n    .collect(Collectors.groupingBy(s -> Arrays.asList(s.getStartRootPartitionId(), s.getEndRootPartitionId())));\nfor (List<DataSegment> group : byRange.values()) {\n  long minorVers = group.stream().map(DataSegment::getMinorVersion).distinct().count();\n  long sizes = group.stream().map(DataSegment::getAtomicUpdateGroupSize).distinct().count();\n  if (minorVers != 1 || sizes != 1) throw new IllegalStateException(\"Mixed generation within a rootPartitionRange\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  TaskLockHelper.verifyRootPartitionIsAdjacentAndAtomicUpdateGroupIsFull(sorted);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"same rootPartitionRange\")) {\n    // re-run full replace of the interval to rebuild a consistent generation\n  } else { throw e; }\n}","preventionTips":["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."],"tags":["druid","atomic-update-group","compaction","root-partition"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}