{"record":{"id":"76cefbdb05e240dc","repo":"apache/druid","slug":"not-enough-direct-memory-please-adjust-xx-maxdi-76cefb","errorCode":null,"errorMessage":"Not enough direct memory.  Please adjust -XX:MaxDirectMemorySize, druid.processing.buffer.sizeBytes, druid.processing.numThreads, or druid.processing.numMergeBuffers: maxDirectMemory[%,d], memoryNeeded[%,d] = druid.processing.buffer.sizeBytes[%,d] * (druid.processing.numMergeBuffers[%,d] + druid.processing.numThreads[%,d] + 1)","messagePattern":"Not enough direct memory\\.  Please adjust -XX:MaxDirectMemorySize, druid\\.processing\\.buffer\\.sizeBytes, druid\\.processing\\.numThreads, or druid\\.processing\\.numMergeBuffers: maxDirectMemory\\[%,d\\], memoryNeeded\\[%,d\\] = druid\\.processing\\.buffer\\.sizeBytes\\[%,d\\] \\* \\(druid\\.processing\\.numMergeBuffers\\[%,d\\] \\+ druid\\.processing\\.numThreads\\[%,d\\] \\+ 1\\)","errorType":"exception","errorClass":"ProvisionException","httpStatus":null,"severity":"critical","filePath":"server/src/main/java/org/apache/druid/guice/DruidProcessingModule.java","lineNumber":201,"sourceCode":"  )\n  {\n    verifyDirectMemory(config, runtimeInfo);\n    return new DefaultBlockingPool<>(\n        new OffheapBufferGenerator(\"result merging\", config.intermediateComputeSizeBytes()),\n        config.getNumMergeBuffers(),\n        config.isParallelMemoryPoolInit()\n    );\n  }\n\n  private static void verifyDirectMemory(final DruidProcessingConfig config, final RuntimeInfo runtimeInfo)\n  {\n    try {\n      final long maxDirectMemory = runtimeInfo.getDirectMemorySizeBytes();\n      final long memoryNeeded = (long) config.intermediateComputeSizeBytes() *\n                                (config.getNumMergeBuffers() + config.getNumThreads() + 1);\n\n      if (maxDirectMemory < memoryNeeded) {\n        throw new ProvisionException(\n            StringUtils.format(\n                \"Not enough direct memory.  Please adjust -XX:MaxDirectMemorySize, druid.processing.buffer.sizeBytes, druid.processing.numThreads, or druid.processing.numMergeBuffers: \"\n                + \"maxDirectMemory[%,d], memoryNeeded[%,d] = druid.processing.buffer.sizeBytes[%,d] * (druid.processing.numMergeBuffers[%,d] + druid.processing.numThreads[%,d] + 1)\",\n                maxDirectMemory,\n                memoryNeeded,\n                config.intermediateComputeSizeBytes(),\n                config.getNumMergeBuffers(),\n                config.getNumThreads()\n            )\n        );\n      }\n    }\n    catch (UnsupportedOperationException e) {\n      log.debug(\"Checking for direct memory size is not support on this platform: %s\", e);\n      log.info(\n          \"Unable to determine max direct memory size. If druid.processing.buffer.sizeBytes is explicitly configured, \"\n          + \"then make sure to set -XX:MaxDirectMemorySize to at least \\\"druid.processing.buffer.sizeBytes * \"\n          + \"(druid.processing.numMergeBuffers[%,d] + druid.processing.numThreads[%,d] + 1)\\\", \"","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/guice/DruidProcessingModule.java#L183-L219","documentation":"DruidProcessingModule.verifyDirectMemory runs at Guice provision time on processing nodes (historicals/peons) and requires max direct memory >= buffer.sizeBytes * (numMergeBuffers + numThreads + 1). If MaxDirectMemorySize is too small, startup fails with this ProvisionException listing exact numbers.","triggerScenarios":"Starting a historical/task JVM where druid.processing.buffer.sizeBytes * (druid.processing.numMergeBuffers + druid.processing.numThreads + 1) exceeds -XX:MaxDirectMemorySize; triggered by createIntermediateResultsPool or createMergeBufferPool provisioning.","commonSituations":"Containers with small direct memory defaults; increasing numThreads/numMergeBuffers or buffer size without resizing direct memory; Peon workers inheriting too-small -XX:MaxDirectMemorySize.","solutions":["Increase -XX:MaxDirectMemorySize to at least buffer.sizeBytes * (numMergeBuffers + numThreads + 1)","Reduce druid.processing.numThreads or druid.processing.numMergeBuffers","Reduce druid.processing.buffer.sizeBytes","Use the numbers in the error message to compute the exact required size"],"exampleFix":"// before\n-XX:MaxDirectMemorySize=2g  # with sizeBytes=1g, numThreads=5, mergeBuffers=2 -> needs 8g\n// after\n-XX:MaxDirectMemorySize=8g","handlingStrategy":"validation","validationCode":"long bufferBytes = config.intermediateComputeSizeBytes();\nlong needed = bufferBytes * (config.getNumMergeBuffers() + config.getNumThreads() + 1L);\nif (runtimeInfo.getDirectMemorySizeBytes() < needed) {\n  throw new IllegalStateException(\"raise -XX:MaxDirectMemorySize to >= \" + needed);\n}","typeGuard":null,"tryCatchPattern":"try {\n  injector = makeInjector();\n} catch (ProvisionException e) {\n  if (e.getMessage().contains(\"Not enough direct memory\")) {\n    log.error(\"Set -XX:MaxDirectMemorySize >= sizeBytes*(numMergeBuffers+numThreads+1)\");\n    throw e;\n  }\n  throw e;\n}","preventionTips":["Compute required direct memory in deployment templates: sizeBytes*(numMergeBuffers+numThreads+1)","Keep -XX:MaxDirectMemorySize explicit on historicals and peons","Re-validate after any change to numThreads, numMergeBuffers, or buffer.sizeBytes","Watch direct memory usage metrics in production"],"tags":["memory","configuration","startup"],"backgroundTag":"invalid-config-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}