quarkusio/quarkus · error · IllegalStateException

Already registered on a broadcaster

Error message

Already registered on a broadcaster

What it means

SseEventSinkImpl.register(broadcaster) throws IllegalStateException if the sink is already associated with an SseBroadcaster. A sink may belong to at most one broadcaster for its lifetime, per the JAX-RS SSE model.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseEventSinkImpl.java:80

            context.suspend();
            response.write(EMPTY_BUFFER, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) {
                    if (throwable == null) {
                        context.resume();
                    } else {
                        context.resume(throwable);
                    }
                    // I don't think we should be firing the exception on the broadcaster here
                }
            });
        }
        response.addCloseHandler(this::close);
    }

    void register(SseBroadcasterImpl broadcaster) {
        if (this.broadcaster != null)
            throw new IllegalStateException("Already registered on a broadcaster");
        this.broadcaster = broadcaster;
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Register each sink exactly once, on the broadcaster that owns its connection.
  2. Track registration state in application code and skip if already registered.
  3. On reconnect, use the newly injected SseEventSink instance rather than reusing the old one.
  4. Catch IllegalStateException and treat the second registration as a no-op if idempotency is desired.

Example fix

// before
broadcasterA.register(sink);
broadcasterB.register(sink); // IllegalStateException
// after
broadcasterA.register(sink); // one broadcaster per sink
// broadcast to other clients via broadcasterA too, or create a new sink for broadcasterB
Defensive patterns

Strategy: validation

Validate before calling

if (registeredSinks.contains(sink)) {
    return; // already on a broadcaster
}

Type guard

boolean isUnregistered(SseEventSinkImpl s) {
    return s != null && !s.isClosed();
}

Try / catch

try {
    broadcaster.register(sink);
} catch (IllegalStateException e) {
    log.debug("Sink already registered; skipping");
}

Prevention

When it happens

Trigger: Calling broadcaster.register(sink) twice — e.g. the same injected SseEventSink registered on two broadcasters, or re-registering after a retry/reconnect handler ran twice.

Common situations: Re-registration on client reconnect without a new sink; registering the sink in both a resource method and a lifecycle listener; CDI scope mistakes causing a shared sink instance across multiple registration paths.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/052dcbecccd33208. Report an issue: GitHub.