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

  1. 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).
  2. 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(...).
  3. For custom EventProcessor implementations, set the exception handler on the processor itself before adding it to the Disruptor rather than through ExceptionHandlerSetting.
  4. 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

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


AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14). Data as JSON: /api/errors/0f586da85ef1a4d9. Report an issue: GitHub.