{"record":{"id":"53cac6e4d8b0a3ef","repo":"apache/druid","slug":"s-this-can-occur-when-the-overhead-from-too-many","errorCode":null,"errorMessage":"%s.\nThis can occur when the overhead from too many intermediary segment persists becomes to great to have enough space to process additional input rows. This check, along with metering the overhead of these objects to factor into the 'maxBytesInMemory' computation, can be disabled by setting 'skipBytesInMemoryOverheadCheck' to 'true' (note that doing so might allow the task to naturally encounter a 'java.lang.OutOfMemoryError'). Alternatively, 'maxBytesInMemory' can be increased which will cause an increase in heap footprint, but will allow for more intermediary segment persists to occur before reaching this condition.","messagePattern":"%s\\.\nThis can occur when the overhead from too many intermediary segment persists becomes to great to have enough space to process additional input rows\\. This check, along with metering the overhead of these objects to factor into the 'maxBytesInMemory' computation, can be disabled by setting 'skipBytesInMemoryOverheadCheck' to 'true' \\(note that doing so might allow the task to naturally encounter a 'java\\.lang\\.OutOfMemoryError'\\)\\. Alternatively, 'maxBytesInMemory' can be increased which will cause an increase in heap footprint, but will allow for more intermediary segment persists to occur before reaching this condition\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"server/src/main/java/org/apache/druid/segment/realtime/appenderator/StreamAppenderator.java","lineNumber":431,"sourceCode":"              getTotalRowCount(),\n              bytesCurrentlyInMemory.get(),\n              bytesToBePersisted,\n              maxBytesTuningConfig\n          );\n          final String errorMessage = StringUtils.format(\n              \"%s.\\nThis can occur when the overhead from too many intermediary segment persists becomes to \"\n              + \"great to have enough space to process additional input rows. This check, along with metering the overhead \"\n              + \"of these objects to factor into the 'maxBytesInMemory' computation, can be disabled by setting \"\n              + \"'skipBytesInMemoryOverheadCheck' to 'true' (note that doing so might allow the task to naturally encounter \"\n              + \"a 'java.lang.OutOfMemoryError'). Alternatively, 'maxBytesInMemory' can be increased which will cause an \"\n              + \"increase in heap footprint, but will allow for more intermediary segment persists to occur before \"\n              + \"reaching this condition.\",\n              alertMessage\n          );\n          log.makeAlert(alertMessage)\n             .addData(\"dataSource\", schema.getDataSource())\n             .emit();\n          throw new RuntimeException(errorMessage);\n        }\n\n        Futures.addCallback(\n            persistAll(committerSupplier == null ? null : committerSupplier.get()),\n            new FutureCallback<>()\n            {\n              @Override\n              public void onSuccess(@Nullable Object result)\n              {\n                // do nothing\n              }\n\n              @Override\n              public void onFailure(Throwable t)\n              {\n                persistError = t;\n              }\n            },","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/realtime/appenderator/StreamAppenderator.java#L413-L449","documentation":"During add, when a persist is needed, StreamAppenderator checks whether adding the persist overhead to maxBytesInMemory would exceed the limit; if so it builds a long errorMessage (prefixed by alertMessage) and throws a RuntimeException. The message explains that intermediary persist overhead consumed the byte budget and suggests skipBytesInMemoryOverheadCheck or raising maxBytesInMemory.","triggerScenarios":"Repeated intermediary persists whose overhead accounting exceeds maxBytesInMemory: many small persists triggered by tuning maxRowsInMemory/maxBytesInMemory/persistPeriod with a small maxBytesInMemory, so overhead + bytes exceeds the limit during add.","commonSituations":"High-cardinality ingestion producing large intermediate state; too-small maxBytesInMemory relative to number of open sinks; frequent persistEveryNRows causing many concurrent hydrant persists.","solutions":["Increase maxBytesInMemory in tuningConfig to give headroom for persist overhead.","Set skipBytesInMemoryOverheadCheck: true in tuningConfig to disable the overhead accounting (accepting OOM risk).","Reduce persist frequency (raise maxRowsInMemory / maxBytesInMemory for persists) so fewer intermediary persists occur."],"exampleFix":"// before\ntuningConfig: { maxBytesInMemory: 100000000 }\n\n// after\ntuningConfig: { maxBytesInMemory: 1000000000, skipBytesInMemoryOverheadCheck: false } // or skipBytesInMemoryOverheadCheck: true","handlingStrategy":"validation","validationCode":"// ensure tuning headroom before task start\nif (estimatedPersistOverhead >= maxBytesInMemory) {\n  throw new IllegalArgumentException(\"maxBytesInMemory too small for persist overhead\");\n}","typeGuard":null,"tryCatchPattern":"try { appenderator.add(id, row, supplier, true) } catch (RuntimeException e) { if (e.getMessage().contains(\"skipBytesInMemoryOverheadCheck\")) { resubmitWithLargerMaxBytesInMemory(e); } else throw e; }","preventionTips":["Set maxBytesInMemory generously (default 1/6 of JVM heap)","Avoid many tiny intermediary persists","Watch the druid/ingest/actions/movedToHeap and persist metrics"],"tags":["druid","memory","ingestion","tuning"],"backgroundTag":"memory-limit-exceeded","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"}