{"record":{"id":"9da53903f5553d08","repo":"apache/druid","slug":"unused-segment-s-has-version-s-task-version","errorCode":null,"errorMessage":"Unused segment[%s] has version[%s] > task version[%s]","messagePattern":"Unused segment\\[(.+?)\\] has version\\[(.+?)\\] > task version\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/ArchiveTask.java","lineNumber":88,"sourceCode":"  public Set<ResourceAction> getInputSourceResources()\n  {\n    return ImmutableSet.of();\n  }\n\n  @Override\n  public TaskStatus runTask(TaskToolbox toolbox) throws Exception\n  {\n    final TaskLock myLock = getAndCheckLock(toolbox);\n\n    // List unused segments\n    final List<DataSegment> unusedSegments = toolbox\n        .getTaskActionClient()\n        .submit(new RetrieveUnusedSegmentsAction(myLock.getDataSource(), myLock.getInterval(), null, null, null));\n\n    // Verify none of these segments have versions > lock version\n    for (final DataSegment unusedSegment : unusedSegments) {\n      if (unusedSegment.getVersion().compareTo(myLock.getVersion()) > 0) {\n        throw new ISE(\n            \"Unused segment[%s] has version[%s] > task version[%s]\",\n            unusedSegment.getId(),\n            unusedSegment.getVersion(),\n            myLock.getVersion()\n        );\n      }\n\n      log.info(\"OK to archive segment: %s\", unusedSegment.getId());\n    }\n\n    // Move segments\n    for (DataSegment segment : unusedSegments) {\n      final DataSegment archivedSegment = toolbox.getDataSegmentArchiver().archive(segment);\n      if (archivedSegment != null) {\n        toolbox.getTaskActionClient().submit(new SegmentMetadataUpdateAction(ImmutableSet.of(archivedSegment)));\n      } else {\n        log.info(\"No action was taken for [%s]\", segment.getId());\n      }","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/ArchiveTask.java#L70-L106","documentation":"Thrown by ArchiveTask.runTask after retrieving unused segments: a segment in the target interval has a version newer than the task's lock version. Archiving such segments would hide data written by a more recent (shadowing) writer, so Druid aborts to avoid archiving segments that newer versions are supposed to supersede.","triggerScenarios":"Running an archive (or kill-style) task over an interval where a higher-version segment was written after the archive task acquired its lock — e.g., overlapping re-ingestion with a later version, or a manually chosen task version older than existing unused segments.","commonSituations":"Re-running failed compaction/replacement tasks that leave behind mixed-version unused segments; hand-crafted archive tasks with an explicit version string; race between a replacement task committing and an archive task scanning the interval.","solutions":["Retry the archive task so it acquires a fresh, current-version lock after newer writes finish.","Exclude or first kill the higher-version segments, then archive the remaining ones.","Set the archive task's version equal to or greater than the max segment version in the interval.","Inspect segment versions (sys.segments or coordinator API) for the interval before launching the archive task."],"exampleFix":"// before: fixed old version\nArchiveTask task = new ArchiveTask(id, ds, new Interval(\"2023/2024\"), null, \"old-version\");\n// after: bump/retry so lock version >= segment versions\nArchiveTask task = new ArchiveTask(id, ds, new Interval(\"2023/2024\"), null, null); // derive from current lock","handlingStrategy":"retry","validationCode":"final List<DataSegment> unused = client.submit(new RetrieveUnusedSegmentsAction(ds, interval, null, null, null));\nfinal String maxVersion = unused.stream().map(s -> s.getVersion()).max(Comparator.naturalOrder()).orElse(\"\");\nif (lockVersion.compareTo(maxVersion) < 0) { /* postpone or raise task version */ }","typeGuard":null,"tryCatchPattern":"try { archiveTask.run(...); } catch (ISE e) { if (e.getMessage().contains(\"has version\")) { retry after newer tasks complete; } else throw e; }","preventionTips":["Run archive/kill tasks only after all replacement tasks for the interval have completed.","Query sys.segments for max version in the interval before archiving.","Avoid hand-pinning task versions; let Druid derive them from locks."],"tags":["druid","segment-versioning","archival","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}