{"record":{"id":"feada387aadbe15a","repo":"apache/druid","slug":"timeline-segments-with-the-same-interval-should-ha","errorCode":null,"errorMessage":"Timeline segments with the same interval should have the same version: existing version[%s] vs new segment[%s]","messagePattern":"Timeline segments with the same interval should have the same version: existing version\\[(.+?)\\] vs new segment\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/input/DruidInputSource.java","lineNumber":625,"sourceCode":"  public static List<TimelineObjectHolder<String, DataSegment>> getTimelineForSegmentIds(\n      CoordinatorClient coordinatorClient,\n      String dataSource,\n      List<WindowedSegmentId> segmentIds\n  )\n  {\n    final SortedMap<Interval, TimelineObjectHolder<String, DataSegment>> timeline = new TreeMap<>(\n        Comparators.intervalsByStartThenEnd()\n    );\n    for (WindowedSegmentId windowedSegmentId : Preconditions.checkNotNull(segmentIds, \"segmentIds\")) {\n      final DataSegment segment = FutureUtils.getUnchecked(\n          coordinatorClient.fetchSegment(dataSource, windowedSegmentId.getSegmentId(), false),\n          true\n      );\n      for (Interval interval : windowedSegmentId.getIntervals()) {\n        final TimelineObjectHolder<String, DataSegment> existingHolder = timeline.get(interval);\n        if (existingHolder != null) {\n          if (!existingHolder.getVersion().equals(segment.getVersion())) {\n            throw new ISE(\"Timeline segments with the same interval should have the same version: \" +\n                          \"existing version[%s] vs new segment[%s]\", existingHolder.getVersion(), segment);\n          }\n          existingHolder.getObject().add(segment.getShardSpec().createChunk(segment));\n        } else {\n          timeline.put(\n              interval,\n              new TimelineObjectHolder<>(\n                  interval,\n                  segment.getInterval(),\n                  segment.getVersion(),\n                  new PartitionHolder<>(segment.getShardSpec().createChunk(segment))\n              )\n          );\n        }\n      }\n    }\n\n    // Validate that none of the given windows overlaps (except for when multiple segments share exactly the","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/input/DruidInputSource.java#L607-L643","documentation":"When building an in-memory timeline from explicitly provided segment IDs, DruidInputSource requires all segments covering the same interval to share the same version. A segment ID resolving to a different version for an existing interval throws IllegalStateException, because mixed-version chunks cannot form one timeline holder.","triggerScenarios":"Passing a 'segments' list that mixes segment versions for the same interval — e.g. listing both an overshadowed older-version segment and its replacement with identical intervals.","commonSituations":"Hand-picking segment IDs from metadata after re-indexing/compaction and accidentally including superseded versions; stale segment lists captured before a compaction replaced versions.","solutions":["Remove segment IDs of superseded (older) versions; keep only the latest version per interval.","Regenerate the segment list from the current timeline/metadata so only winning versions are included.","Switch to 'interval'-based selection so normal timeline overshadowing logic applies."],"exampleFix":"// before\nsegments = [\"ds_2020-01-01_2020-01-02_2020-01-03_v0_1\", \"ds_2020-01-01_2020-01-02_2020-01-03_v1_1\"]\n// after\nsegments = [\"ds_2020-01-01_2020-01-02_2020-01-03_v1_1\"]","handlingStrategy":"validation","validationCode":"Map<Interval, String> versions = new HashMap<>();\nfor (String id : segmentIds) {\n  DataSegment seg = loadSegment(id);\n  String prev = versions.putIfAbsent(seg.getInterval(), seg.getVersion());\n  if (prev != null && !prev.equals(seg.getVersion())) {\n    throw new IllegalStateException(\"Mixed versions for \" + seg.getInterval());\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  List<DataSegment> timeline = inputSource.createTimeline();\n} catch (IllegalStateException e) {\n  // drop superseded-version segment ids and retry with latest versions only\n}","preventionTips":["Derive segment ID lists from the current timeline, not stale snapshots.","Exclude overshadowed (older-version) segments when enumerating IDs.","Prefer 'interval' selection when version consistency cannot be guaranteed."],"tags":["druid","timeline","segment-versions","illegal-state"],"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"}