apache/druid · critical · RuntimeException
. This can occur when the overhead from too many…
Error message
%s. This 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.
What it means
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.
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.
Example fix
// before
tuningConfig: { maxBytesInMemory: 100000000 }
// after
tuningConfig: { maxBytesInMemory: 1000000000, skipBytesInMemoryOverheadCheck: false } // or skipBytesInMemoryOverheadCheck: true Defensive patterns
Strategy: validation
Validate before calling
// ensure tuning headroom before task start
if (estimatedPersistOverhead >= maxBytesInMemory) {
throw new IllegalArgumentException("maxBytesInMemory too small for persist overhead");
} Try / catch
try { appenderator.add(id, row, supplier, true) } catch (RuntimeException e) { if (e.getMessage().contains("skipBytesInMemoryOverheadCheck")) { resubmitWithLargerMaxBytesInMemory(e); } else throw e; } Prevention
- Set maxBytesInMemory generously (default 1/6 of JVM heap)
- Avoid many tiny intermediary persists
- Watch the druid/ingest/actions/movedToHeap and persist metrics
When it happens
Trigger: 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.
Common situations: High-cardinality ingestion producing large intermediate state; too-small maxBytesInMemory relative to number of open sinks; frequent persistEveryNRows causing many concurrent hydrant persists.
Related errors
- Attempt to add row to swapped-out sink for segment
- Bloom filter aggregators are query-time only
- buffer for list is too small, was
- Can't find pushedSegments for segment
- Can't find segmentsForSequence for sequence
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/53cac6e4d8b0a3ef.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/realtime/appenderator/StreamAppenderator.java:431
getTotalRowCount(),
bytesCurrentlyInMemory.get(),
bytesToBePersisted,
maxBytesTuningConfig
);
final String errorMessage = StringUtils.format(
"%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.",
alertMessage
);
log.makeAlert(alertMessage)
.addData("dataSource", schema.getDataSource())
.emit();
throw new RuntimeException(errorMessage);
}
Futures.addCallback(
persistAll(committerSupplier == null ? null : committerSupplier.get()),
new FutureCallback<>()
{
@Override
public void onSuccess(@Nullable Object result)
{
// do nothing
}
@Override
public void onFailure(Throwable t)
{
persistError = t;
}
},View on GitHub (pinned to 9b90983fd2)