LMAX-Exchange/disruptor · error · RuntimeException
EventProcessor: {} is not a BatchEventProcessor and does not
Error message
EventProcessor: {} is not a BatchEventProcessor and does not support exception handlers What it means
Thrown by ExceptionHandlerSetting.with (src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java:59) when disruptor.handleExceptionsFor(eventHandler).with(exceptionHandler) is called but the processor registered for that event handler is not a BatchEventProcessor. Only BatchEventProcessor supports attaching an ExceptionHandler through the DSL; a WorkProcessor (worker-pool consumers) manages its own FatalExceptionHandler internally and rejects this path.
Source
Thrown at src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java:59
}
/**
* Specify the {@link ExceptionHandler} to use with the event handler.
*
* @param exceptionHandler the exception handler to use.
*/
@SuppressWarnings("unchecked")
public void with(final ExceptionHandler<? super T> exceptionHandler)
{
final EventProcessor eventProcessor = consumerRepository.getEventProcessorFor(handlerIdentity);
if (eventProcessor instanceof BatchEventProcessor)
{
((BatchEventProcessor<T>) eventProcessor).setExceptionHandler(exceptionHandler);
consumerRepository.getBarrierFor(handlerIdentity).alert();
}
else
{
throw new RuntimeException(
"EventProcessor: " + eventProcessor + " is not a BatchEventProcessor " +
"and does not support exception handlers");
}
}
}
View on GitHub (pinned to c871ca4982)
Solutions
- If the consumer is a WorkHandler (worker pool), remove handleExceptionsFor and instead catch exceptions inside WorkHandler.onEvent(), or configure exception handling at the handler level directly (WorkProcessor defaults to FatalExceptionHandler).
- If you want DSL-managed ExceptionHandler semantics, register the consumer as a plain EventHandler via disruptor.handleEventsWith(eventHandler) so a BatchEventProcessor backs it, then call handleExceptionsFor(...).with(...).
- For custom EventProcessor implementations, set the exception handler on the processor itself before adding it to the Disruptor rather than through ExceptionHandlerSetting.
- Check consumerRepository wiring if neither applies: verify which registration path produced the handler identity you passed to handleExceptionsFor.
Example fix
// before (handler is a WorkHandler registered via handleEventsWithWorkerPool)
disruptor.handleEventsWithWorkerPool(workers).then(...);
disruptor.handleExceptionsFor(workHandler).with(myExceptionHandler); // throws: not a BatchEventProcessor
// after (handle exceptions inside the WorkHandler)
public class MyWorkHandler implements WorkHandler<Event> {
@Override
public void onEvent(Event event) {
try {
process(event);
} catch (Exception e) {
myExceptionHandler.handleEventException(e, event.ordinal(), event);
}
}
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before calling handleExceptionsFor(...).with(...), confirm the consumer is EventHandler-based // (i.e. registered via handleEventsWith, backed by BatchEventProcessor) // Only plain EventHandler registrations can use the DSL exception-handler path.
Type guard
boolean supportsDslExceptionHandler = myHandler instanceof EventHandler
&& !(registeredViaWorkerPool); // track registration path when wiring the Disruptor Try / catch
try {
disruptor.handleExceptionsFor(handler).with(exceptionHandler);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("not a BatchEventProcessor")) {
// consumer is a WorkProcessor/custom processor: handle exceptions inside the handler instead
log.warn("DSL exception handlers unsupported for {}; using in-handler handling", handler);
} else {
throw e;
}
} Prevention
- Keep exception handling colocated with consumption style: ExceptionHandler via DSL only for EventHandler/BatchEventProcessor; try-catch inside onEvent for WorkHandler.
- When migrating from handleEventsWith to handleEventsWithWorkerPool, grep for handleExceptionsFor calls and remove/adapt them.
- Remember WorkProcessor already defaults to FatalExceptionHandler, so unhandled worker exceptions never disappear silently.
When it happens
Trigger: Calling disruptor.handleExceptionsFor(handler).with(exHandler) where 'handler' was registered via disruptor.handleEventsWithWorkerPool(...).withWorkHandler(...) — the consumer repository resolves the WorkProcessor for that identity, the instanceof BatchEventProcessor check fails, and the RuntimeException is thrown. Also calling it for any custom EventProcessor wired manually via disruptor.handleEventsWith(customProcessor).
Common situations: Migrating from handleEventsWith (BatchEventProcessor) to handleEventsWithWorkerPool (WorkProcessor) while keeping the existing handleExceptionsFor call; passing a custom EventProcessor implementation into the DSL and then trying to set an exception handler on it; tutorial copy-paste where the example used EventHandler but the project uses WorkHandler.
Related errors
- setDefaultExceptionHandler can not be used after handleExcep
- Rewindable Exception thrown from a non-rewindable event hand
- Failed to create thread to run: {}
- value must be a positive number
- Already running
AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14).
Data as JSON: /api/errors/0f586da85ef1a4d9.
Report an issue: GitHub.