{"record":{"id":"707215b89796befc","repo":"apache/druid","slug":"number-of-locks-exceeded-maxallowedlockcount-s","errorCode":null,"errorMessage":"Number of locks exceeded maxAllowedLockCount [%s].","messagePattern":"Number of locks exceeded maxAllowedLockCount \\[(.+?)\\]\\.","errorType":"exception","errorClass":"MaxAllowedLocksExceededException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java","lineNumber":476,"sourceCode":"      intervalIterator = JodaUtils.condenseIntervals(intervals).iterator();\n    } else {\n      IntervalsByGranularity intervalsByGranularity = new IntervalsByGranularity(intervals, segmentGranularity);\n      // the following is calling a condense that does not materialize the intervals:\n      intervalIterator = JodaUtils.condensedIntervalsIterator(intervalsByGranularity.granularityIntervalsIterator());\n    }\n\n    // Intervals are already condensed to avoid creating too many locks.\n    // Intervals are also sorted and thus it's safe to compare only the previous interval and current one for dedup.\n    Interval prev = null;\n    int locksAcquired = 0;\n    while (intervalIterator.hasNext()) {\n      final Interval cur = intervalIterator.next();\n      if (prev != null && cur.equals(prev)) {\n        continue;\n      }\n\n      if (maxAllowedLockCount >= 0 && locksAcquired >= maxAllowedLockCount) {\n        throw new MaxAllowedLocksExceededException(maxAllowedLockCount);\n      }\n\n      prev = cur;\n      final TaskLockType taskLockType = determineLockType(LockGranularity.TIME_CHUNK);\n      final TaskLock lock = client.submit(new TimeChunkLockTryAcquireAction(taskLockType, cur));\n      if (lock == null) {\n        return false;\n      }\n      lock.assertNotRevoked();\n      locksAcquired++;\n      intervalToLockVersion.put(cur, lock.getVersion());\n    }\n    return true;\n  }\n\n  private TaskLockHelper createLockHelper(LockGranularity lockGranularity)\n  {\n    return new TaskLockHelper(","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java#L458-L494","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\n\"tuningConfig\": {\"type\": \"parallel_index\", \"maxAllowedLockCount\": 10}\n// after\n\"tuningConfig\": {\"type\": \"parallel_index\", \"maxAllowedLockCount\": 1000}","handlingStrategy":"validation","validationCode":"long buckets = ChronoUnit.HOURS.between(start, end); // per segmentGranularity\nint maxAllowedLockCount = tuningConfig.getMaxAllowedLockCount();\nif (maxAllowedLockCount >= 0 && buckets > maxAllowedLockCount) {\n  throw new IllegalArgumentException(\"Intervals span \" + buckets + \" locks > maxAllowedLockCount \" + maxAllowedLockCount);\n}","typeGuard":null,"tryCatchPattern":"try {\n  runIngestion(spec);\n} catch (MaxAllowedLocksExceededException e) {\n  // raise maxAllowedLockCount or coarsen segmentGranularity, then resubmit\n}","preventionTips":["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."],"tags":["indexing-service","locks","tuning-config"],"backgroundTag":"value-out-of-range","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"}