{"record":{"id":"0f586da85ef1a4d9","repo":"LMAX-Exchange/disruptor","slug":"eventprocessor-is-not-a-batcheventprocessor-an","errorCode":null,"errorMessage":"EventProcessor: {} is not a BatchEventProcessor and does not support exception handlers","messagePattern":"EventProcessor: (.+?) is not a BatchEventProcessor and does not support exception handlers","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java","lineNumber":59,"sourceCode":"    }\n\n    /**\n     * Specify the {@link ExceptionHandler} to use with the event handler.\n     *\n     * @param exceptionHandler the exception handler to use.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public void with(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        final EventProcessor eventProcessor = consumerRepository.getEventProcessorFor(handlerIdentity);\n        if (eventProcessor instanceof BatchEventProcessor)\n        {\n            ((BatchEventProcessor<T>) eventProcessor).setExceptionHandler(exceptionHandler);\n            consumerRepository.getBarrierFor(handlerIdentity).alert();\n        }\n        else\n        {\n            throw new RuntimeException(\n                \"EventProcessor: \" + eventProcessor + \" is not a BatchEventProcessor \" +\n                \"and does not support exception handlers\");\n        }\n    }\n}\n","sourceCodeStart":41,"sourceCodeEnd":65,"githubUrl":"https://github.com/LMAX-Exchange/disruptor/blob/c871ca49826a6be7ada6957f6fbafcfecf7b1f87/src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java#L41-L65","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before (handler is a WorkHandler registered via handleEventsWithWorkerPool)\ndisruptor.handleEventsWithWorkerPool(workers).then(...);\ndisruptor.handleExceptionsFor(workHandler).with(myExceptionHandler); // throws: not a BatchEventProcessor\n\n// after (handle exceptions inside the WorkHandler)\npublic class MyWorkHandler implements WorkHandler<Event> {\n    @Override\n    public void onEvent(Event event) {\n        try {\n            process(event);\n        } catch (Exception e) {\n            myExceptionHandler.handleEventException(e, event.ordinal(), event);\n        }\n    }\n}","handlingStrategy":"type-guard","validationCode":"// Before calling handleExceptionsFor(...).with(...), confirm the consumer is EventHandler-based\n// (i.e. registered via handleEventsWith, backed by BatchEventProcessor)\n// Only plain EventHandler registrations can use the DSL exception-handler path.","typeGuard":"boolean supportsDslExceptionHandler = myHandler instanceof EventHandler\n    && !(registeredViaWorkerPool); // track registration path when wiring the Disruptor","tryCatchPattern":"try {\n    disruptor.handleExceptionsFor(handler).with(exceptionHandler);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"not a BatchEventProcessor\")) {\n        // consumer is a WorkProcessor/custom processor: handle exceptions inside the handler instead\n        log.warn(\"DSL exception handlers unsupported for {}; using in-handler handling\", handler);\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["java","disruptor","exception-handler","worker-pool","api-misuse"],"backgroundTag":null,"analyzedSha":"c871ca49826a6be7ada6957f6fbafcfecf7b1f87","analyzedAt":"2026-08-14T14:22:36.358Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}