apache/druid · error · IllegalStateException

Unexpected state: Two versions([%s], [%s]) for the same inte

Error message

Unexpected state: Two versions([%s], [%s]) for the same interval[%s]

What it means

While listing the supervisor task's locks, PartialSegmentMergeTask expects at most one lock version per interval. If LockListAction returns two locks with different versions for the same interval, the lock state is inconsistent and the task throws this ISE.

Source

Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/PartialSegmentMergeTask.java:160

    // Group partitionLocations by interval and partitionId
    final Map<Interval, Int2ObjectMap<List<PartitionLocation>>> intervalToBuckets = new HashMap<>();
    for (PartitionLocation location : ioConfig.getPartitionLocations()) {
      intervalToBuckets.computeIfAbsent(location.getInterval(), k -> new Int2ObjectOpenHashMap<>())
                       .computeIfAbsent(location.getBucketId(), k -> new ArrayList<>())
                       .add(location);
    }

    final List<TaskLock> locks = toolbox.getTaskActionClient().submit(
        new SurrogateAction<>(getSupervisorTaskId(), new LockListAction())
    );
    final Map<Interval, String> intervalToVersion = Maps.newHashMapWithExpectedSize(locks.size());
    locks.forEach(lock -> {
      if (lock.isRevoked()) {
        throw new ISE("Lock[%s] is revoked", lock);
      }
      final String mustBeNull = intervalToVersion.put(lock.getInterval(), lock.getVersion());
      if (mustBeNull != null) {
        throw new ISE(
            "Unexpected state: Two versions([%s], [%s]) for the same interval[%s]",
            lock.getVersion(),
            mustBeNull,
            lock.getInterval()
        );
      }
    });

    final Stopwatch fetchStopwatch = Stopwatch.createStarted();
    final Map<Interval, Int2ObjectMap<List<File>>> intervalToUnzippedFiles = fetchSegmentFiles(
        toolbox,
        intervalToBuckets
    );
    final long fetchTime = fetchStopwatch.elapsed(TimeUnit.SECONDS);
    fetchStopwatch.stop();
    LOG.info("Fetch took [%s] seconds", fetchTime);

    final ParallelIndexSupervisorTaskClient taskClient = toolbox.getSupervisorTaskClientProvider().build(

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Kill all tasks holding locks on the affected interval and rerun the ingestion.
  2. Inspect task lock entries in the metadata store for the interval and remove stale/duplicate lock rows if safe (during downtime).
  3. Check whether any recent Druid upgrade left incompatible lock formats; consult upgrade notes.
  4. Avoid submitting tasks with conflicting lock types (forceTimeChunkLock vs segment locks) on the same interval concurrently.
Defensive patterns

Strategy: try-catch

Try / catch

catch (IllegalStateException e) { if (e.getMessage().contains("Two versions") && e.getMessage().contains("for the same interval")) { /* kill tasks on the interval, clean lock state, rerun */ } else { throw e; } }

Prevention

When it happens

Trigger: The task action server returns multiple locks for a single interval - typically after version upgrade/downgrade path bugs, corrupted task lock bookkeeping in the metadata store, or overlapping lock upgrades (e.g. replace-locks + timeChunk locks) for the supervisor task.

Common situations: Running tasks that requested both segment-granularity and chunk-granularity locks for the same interval; Druid version upgrades with lingering lock rows; manual edits or corruption of the druid_tasks/task lock tables.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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