quarkusio/quarkus · error · IllegalArgumentException
Can only work with Quarkus-REST instances: ${sseEventSink}
Error message
Can only work with Quarkus-REST instances: ${sseEventSink} What it means
SseBroadcasterImpl.register() throws IllegalArgumentException when the supplied SseEventSink is not a Quarkus REST (RESTEasy Reactive) SseEventSinkImpl instance. The broadcaster manages internal queues and requires its own implementation, per the JAX-RS SSE contract which restricts broadcaster/sink mixing across providers.
Source
Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java:69
onErrorConsumers.add(onError);
}
@Override
public synchronized void onClose(Consumer<SseEventSink> onClose) {
Objects.requireNonNull(onClose);
checkClosed();
closeConsumers.add(onClose);
}
@Override
public synchronized void register(SseEventSink sseEventSink) {
Objects.requireNonNull(sseEventSink);
checkClosed();
readLock.lock();
try {
checkClosed();
if (!(sseEventSink instanceof SseEventSinkImpl sinkImpl)) {
throw new IllegalArgumentException("Can only work with Quarkus-REST instances: " + sseEventSink);
}
sinkImpl.register(this);
outputQueue.add(sseEventSink);
} finally {
readLock.unlock();
}
}
@Override
public synchronized CompletionStage<?> broadcast(OutboundSseEvent event) {
Objects.requireNonNull(event);
checkClosed();
List<CompletableFuture<?>> cfs = new ArrayList<>(outputQueue.size());
for (SseEventSink eventSink : outputQueue) {
CompletionStage<?> cs;
try {
CompletionStage<?> sendStage = eventSink.send(event);View on GitHub (pinned to e1c734241f)
Solutions
- Obtain the SseEventSink only via injection of the Sse/SseEventSink provided by Quarkus REST.
- In tests, build real SseEventSinkImpl instances or use the Quarkus test facilities instead of mocks.
- Remove wrapper/proxy layers around the sink before registering it.
- Check classpath for conflicting JAX-RS implementations (e.g. classic RESTEasy) supplying their own SseEventSink.
Example fix
// before
SseEventSink sink = mock(SseEventSink.class);
broadcaster.register(sink); // IllegalArgumentException
// after
@Path("stream")
class StreamResource {
@Inject Sse sse;
@GET @Produces(MediaType.SERVER_SENT_EVENTS)
public void stream(@Context SseEventSink sink) {
broadcaster.register(sink); // real Quarkus-REST sink
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(sink instanceof SseEventSinkImpl)) {
throw new IllegalArgumentException("Register only Quarkus-REST SseEventSink instances");
} Type guard
boolean isQuarkusSink(SseEventSink s) {
return s instanceof SseEventSinkImpl;
} Try / catch
try {
broadcaster.register(sink);
} catch (IllegalArgumentException e) {
log.warn("Non Quarkus sink rejected: " + e.getMessage());
} Prevention
- Only inject SseEventSink from Quarkus REST resources
- Avoid mocking SseEventSink in tests; use real instances
- Do not wrap sinks in proxies/decorators
- Check for conflicting JAX-RS SSE implementations on the classpath
When it happens
Trigger: Calling sseBroadcaster.register(sink) with a sink obtained from a different JAX-RS provider, a mock, a custom SseEventSink implementation, or a test double.
Common situations: Unit tests injecting Mockito mocks for SseEventSink; mixing implementations when multiple REST frameworks are on the classpath; wrapping/decorating the sink in a proxy that breaks the instanceof check.
Related errors
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/37474a897786411b.
Report an issue: GitHub.