{"record":{"id":"588bdaef78725b1d","repo":"apache/druid","slug":"new-segment-s-have-a-smaller-minor-version-than","errorCode":null,"errorMessage":"New segment[%s] have a smaller minor version than old segment[%s]","messagePattern":"New segment\\[(.+?)\\] have a smaller minor version than old segment\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentTransactionalInsertAction.java","lineNumber":306,"sourceCode":"      final int newStartRootPartitionId = newSegmentsPerInterval.get(0).getStartRootPartitionId();\n      final int newEndRootPartitionId = newSegmentsPerInterval.get(newSegmentsPerInterval.size() - 1)\n                                                              .getEndRootPartitionId();\n\n      if (oldStartRootPartitionId != newStartRootPartitionId || oldEndRootPartitionId != newEndRootPartitionId) {\n        throw new ISE(\n            \"Root partition range[%d, %d] of new segments doesn't match to root partition range[%d, %d] of old segments\",\n            newStartRootPartitionId,\n            newEndRootPartitionId,\n            oldStartRootPartitionId,\n            oldEndRootPartitionId\n        );\n      }\n\n      newSegmentsPerInterval\n          .forEach(eachNewSegment -> oldSegmentsPerInterval\n              .forEach(eachOldSegment -> {\n                if (eachNewSegment.getMinorVersion() <= eachOldSegment.getMinorVersion()) {\n                  throw new ISE(\n                      \"New segment[%s] have a smaller minor version than old segment[%s]\",\n                      eachNewSegment,\n                      eachOldSegment\n                  );\n                }\n              }));\n    });\n  }\n\n  private static Map<Interval, List<DataSegment>> groupSegmentsByIntervalAndSort(Set<DataSegment> segments)\n  {\n    final Map<Interval, List<DataSegment>> segmentsMap = new HashMap<>();\n    segments.forEach(segment -> segmentsMap.computeIfAbsent(segment.getInterval(), k -> new ArrayList<>())\n                                           .add(segment));\n    segmentsMap.values().forEach(segmentsPerInterval -> segmentsPerInterval.sort((s1, s2) -> {\n      if (s1.getStartRootPartitionId() != s2.getStartRootPartitionId()) {\n        return Integer.compare(s1.getStartRootPartitionId(), s2.getStartRootPartitionId());\n      } else {","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/SegmentTransactionalInsertAction.java#L288-L324","documentation":"In SegmentTransactionalInsertAction.checkWithSegmentLock(), every new segment for an interval must have a strictly greater minor version than each existing (old) segment it replaces. Minor versions order concurrent revisions within the same major version; publishing a segment with an equal or smaller minor version would shadow or tie with existing data, so Druid throws this ISE and aborts the transactional insert.","triggerScenarios":"Retrying an old task whose segment ids carry a minor version already used by segments published by a competing task; two tasks generating segments with the same minor version for the same interval/chunk; replaying a stale publish after another task already upgraded the interval.","commonSituations":"Concurrent overwrite tasks writing to the same time chunk; task retries after partial publish where a newer segment already exists; supervisor tasks racing during failover.","solutions":["Restart the task so it re-allocates fresh segment identifiers with a higher minor version via SEGMENT_ALLOCATE.","Ensure only one task overwrites a given interval at a time; serialize overwrite/compaction jobs.","Kill conflicting already-published segments if they should be replaced, then re-run the task.","Check task retry logic so it does not reuse cached SegmentIdWithShardSpec values across attempts."],"exampleFix":"null","handlingStrategy":"retry","validationCode":"for (SegmentIdWithShardSpec n : newSegments)\n  for (SegmentIdWithShardSpec o : oldSegments)\n    if (n.getMinorVersion() <= o.getMinorVersion())\n      throw new IllegalStateException(\"new segment \" + n + \" must have greater minor version than \" + o);","typeGuard":null,"tryCatchPattern":"try { result = action.perform(task, toolbox); } catch (ISE e) { if (e.getMessage().contains(\"smaller minor version\")) { /* restart task to allocate fresh, higher-version segment ids */ } else throw e; }","preventionTips":["Never cache/reuse SegmentIdWithShardSpec across task attempts.","Serialize overwrite work per time chunk.","Let the task framework reallocate segment ids on retry instead of reusing stale ones.","Monitor for concurrent overwrite tasks targeting the same interval."],"tags":["druid","segment-publish","versioning","lineage"],"backgroundTag":"segment-version-conflict","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"}