LMAX-Exchange/disruptor · error · IllegalStateException

setDefaultExceptionHandler can not be used after handleExcep

Error message

setDefaultExceptionHandler can not be used after handleExceptionsWith

What it means

Thrown by Disruptor.setDefaultExceptionHandler when the default exception handler slot has already been replaced by handleExceptionsWith(...). Internally the default is an ExceptionHandlerWrapper; handleExceptionsWith switches it to a concrete handler permanently, after which setDefaultExceptionHandler can no longer take effect, so the API fails fast rather than silently ignoring you.

Source

Thrown at src/main/java/com/lmax/disruptor/dsl/Disruptor.java:233

    public void handleExceptionsWith(final ExceptionHandler<? super T> exceptionHandler)
    {
        this.exceptionHandler = exceptionHandler;
    }

    /**
     * <p>Specify an exception handler to be used for event handlers and worker pools created by this Disruptor.</p>
     *
     * <p>The exception handler will be used by existing and future event handlers and worker pools created by this Disruptor instance.</p>
     *
     * @param exceptionHandler the exception handler to use.
     */
    @SuppressWarnings("unchecked")
    public void setDefaultExceptionHandler(final ExceptionHandler<? super T> exceptionHandler)
    {
        checkNotStarted();
        if (!(this.exceptionHandler instanceof ExceptionHandlerWrapper))
        {
            throw new IllegalStateException("setDefaultExceptionHandler can not be used after handleExceptionsWith");
        }
        ((ExceptionHandlerWrapper<T>) this.exceptionHandler).switchTo(exceptionHandler);
    }

    /**
     * Override the default exception handler for a specific handler.
     * <pre>disruptorWizard.handleExceptionsIn(eventHandler).with(exceptionHandler);</pre>
     *
     * @param eventHandler the event handler to set a different exception handler for.
     * @return an ExceptionHandlerSetting dsl object - intended to be used by chaining the with method call.
     */
    public ExceptionHandlerSetting<T> handleExceptionsFor(final EventHandlerIdentity eventHandler)
    {
        return new ExceptionHandlerSetting<>(eventHandler, consumerRepository);
    }

    /**
     * <p>Create a group of event handlers to be used as a dependency.

View on GitHub (pinned to c871ca4982)

Solutions

  1. Use only one of the two APIs per Disruptor instance: prefer setDefaultExceptionHandler and per-handler overrides via handleExceptionsFor(...).with(...).
  2. If a library you call uses handleExceptionsWith, configure your handlers with handleExceptionsFor instead of the global setter.
  3. Audit startup code for both calls; remove the redundant one.

Example fix

// before
disruptor.handleExceptionsWith(new FatalExceptionHandler());
disruptor.setDefaultExceptionHandler(new LogExceptionHandler<>()); // IllegalStateException

// after
disruptor.setDefaultExceptionHandler(new LogExceptionHandler<>());
disruptor.handleExceptionsFor(myHandler).with(new FatalExceptionHandler());
Defensive patterns

Strategy: validation

Validate before calling

// pick ONE style per Disruptor instance
disruptor.setDefaultExceptionHandler(defaultHandler);            // style A
// or: disruptor.handleExceptionsWith(defaultHandler);           // style B (terminal)
// per-handler overrides are always allowed:
disruptor.handleExceptionsFor(handlerA).with(specificHandler);

Prevention

When it happens

Trigger: Calling disruptor.handleExceptionsWith(handler) and later disruptor.setDefaultExceptionHandler(other) on the same Disruptor instance (before start). The reverse order alone is fine; it is the combination in this order that throws.

Common situations: Library code calls handleExceptionsWith while application code also calls setDefaultExceptionHandler (or vice versa across versions); upgrading Disruptor 3.x -> 4.x where exception-handler configuration semantics were tightened; copy-pasted setup from two examples using different APIs.

Related errors


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