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
- Increase maxAllowedLockCount in the parallel-index tuningConfig to exceed the number of buckets your intervals need.
- Coarsen segmentGranularity (e.g. day instead of minute) to reduce the number of distinct locks.
- Split the ingestion into multiple tasks, each covering a smaller interval range within the limit.
- 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
- Compute expected bucket count (interval span / segmentGranularity) before submitting and size maxAllowedLockCount accordingly.
- Use -1 to disable the cap only when lock volume is known to be modest.
- Split very long time ranges into multiple sequential ingestion tasks.
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
- Cannot start; not ready!
- Lock revoked: [%s]
- Cannot find a version for interval[%s]
- Lock dataSource[%s] != task dataSource[%s]
- Can't find surrogate task[%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/707215b89796befc.
Report an issue: GitHub.