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

  1. Increase maxBytesInMemory in tuningConfig to give headroom for persist overhead.
  2. Set skipBytesInMemoryOverheadCheck: true in tuningConfig to disable the overhead accounting (accepting OOM risk).
  3. 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

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


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)