apache/druid · error · MaxAllowedLocksExceededException

Number of locks exceeded maxAllowedLockCount [%s].

Error message

Number of locks exceeded maxAllowedLockCount [%s].

What it means

tryTimeChunkLock iterates the intervals to lock one granularity bucket at a time and enforces maxAllowedLockCount from ParallelIndexTuningConfig. When the number of distinct time-chunk locks needed would exceed the configured maximum, it throws MaxAllowedLocksExceededException with the limit. This protects the overlord and metadata store from tasks attempting to acquire an unbounded number of locks.

Source

Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java:476

      intervalIterator = JodaUtils.condenseIntervals(intervals).iterator();
    } else {
      IntervalsByGranularity intervalsByGranularity = new IntervalsByGranularity(intervals, segmentGranularity);
      // the following is calling a condense that does not materialize the intervals:
      intervalIterator = JodaUtils.condensedIntervalsIterator(intervalsByGranularity.granularityIntervalsIterator());
    }

    // Intervals are already condensed to avoid creating too many locks.
    // Intervals are also sorted and thus it's safe to compare only the previous interval and current one for dedup.
    Interval prev = null;
    int locksAcquired = 0;
    while (intervalIterator.hasNext()) {
      final Interval cur = intervalIterator.next();
      if (prev != null && cur.equals(prev)) {
        continue;
      }

      if (maxAllowedLockCount >= 0 && locksAcquired >= maxAllowedLockCount) {
        throw new MaxAllowedLocksExceededException(maxAllowedLockCount);
      }

      prev = cur;
      final TaskLockType taskLockType = determineLockType(LockGranularity.TIME_CHUNK);
      final TaskLock lock = client.submit(new TimeChunkLockTryAcquireAction(taskLockType, cur));
      if (lock == null) {
        return false;
      }
      lock.assertNotRevoked();
      locksAcquired++;
      intervalToLockVersion.put(cur, lock.getVersion());
    }
    return true;
  }

  private TaskLockHelper createLockHelper(LockGranularity lockGranularity)
  {
    return new TaskLockHelper(

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Increase maxAllowedLockCount in the parallel-index tuningConfig to exceed the number of buckets your intervals need.
  2. Coarsen segmentGranularity (e.g. day instead of minute) to reduce the number of distinct locks.
  3. Split the ingestion into multiple tasks, each covering a smaller interval range within the limit.
  4. Set maxAllowedLockCount to -1 to disable the cap (only if the overlord can tolerate the lock volume).

Example fix

// before
"tuningConfig": {"type": "parallel_index", "maxAllowedLockCount": 10}
// after
"tuningConfig": {"type": "parallel_index", "maxAllowedLockCount": 1000}
Defensive patterns

Strategy: validation

Validate before calling

long buckets = ChronoUnit.HOURS.between(start, end); // per segmentGranularity
int maxAllowedLockCount = tuningConfig.getMaxAllowedLockCount();
if (maxAllowedLockCount >= 0 && buckets > maxAllowedLockCount) {
  throw new IllegalArgumentException("Intervals span " + buckets + " locks > maxAllowedLockCount " + maxAllowedLockCount);
}

Try / catch

try {
  runIngestion(spec);
} catch (MaxAllowedLocksExceededException e) {
  // raise maxAllowedLockCount or coarsen segmentGranularity, then resubmit
}

Prevention

When it happens

Trigger: Running a parallel index (or other batch) task whose input spans more distinct segment-granularity buckets than maxAllowedLockCount (default limits apply), because the time range is long relative to segmentGranularity.

Common situations: Ingesting months/years of data with hourly or minute segmentGranularity while maxAllowedLockCount is left small; narrowing segmentGranularity during a re-index without raising the limit; explicit intervals list with many small chunks.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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