quarkusio/quarkus · error · java.lang.IllegalStateException
Was already open
Error message
Was already open
What it means
SseEventSourceImpl.registerAfterRequest throws this IllegalStateException if the source's isOpen flag is already true when the HTTP client tries to register the SSE listener on the response. Each SSE event source may only open one stream; opening it twice is a lifecycle misuse.
Source
Thrown at independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/SseEventSourceImpl.java:152
delayMs = Math.min(serverDelayMs, Math.max(defaultDelayMs, 300_000));
}
} catch (NumberFormatException e) {
// unparseable — use default
}
}
Vertx vertx = webTarget.getRestClient().getVertx();
if (timerId != -1) {
vertx.cancelTimer(timerId);
}
timerId = vertx.setTimer(delayMs, this);
}
/**
* Allows the HTTP client to register for SSE after it has made the request
*/
synchronized void registerAfterRequest(HttpClientResponse vertxClientResponse) {
if (isOpen)
throw new IllegalStateException("Was already open");
isOpen = true;
registerOnClient(vertxClientResponse);
}
private void registerOnClient(HttpClientResponse vertxClientResponse) {
// make sure we get exceptions on the response, like close events, otherwise they
// will be logged as errors by vertx
vertxClientResponse.exceptionHandler(t -> {
if (t == ConnectionBase.CLOSED_EXCEPTION) {
// we can ignore this one since we registered a closeHandler
} else {
receiveThrowable(t);
}
});
// since we registered our exception handler, let's remove the request exception handler
// that is set in ClientSendRequestHandler
vertxClientResponse.request().exceptionHandler(null);
connection = vertxClientResponse.request().connection();View on GitHub (pinned to e1c734241f)
Solutions
- Create a new SseEventSource (target.sse()) for each connection/open call
- Close the existing source before attempting to register/open again
- Guard calls with source.isOpen() before opening
Example fix
// before SseEventSource source = sseSource; // reused source.open(); // second call -> Was already open // after SseEventSource source = webTarget.sse(); // fresh instance source.open();
Defensive patterns
Strategy: try-catch
Validate before calling
if (source.isOpen()) {
source = webTarget.sse(); // replace with a fresh source
}
source.open(); Type guard
SseEventSource ensureClosed(SseEventSource src) {
if (src != null && src.isOpen()) src.close();
return src;
} Try / catch
try {
source.open();
} catch (IllegalStateException e) {
if ("Was already open".equals(e.getMessage())) {
source.close();
source = webTarget.sse();
source.open();
} else throw e;
} Prevention
- Create a new SseEventSource per connection; never reopen an open source
- Close sources in a finally block or on cancellation
- Guard with source.isOpen() before open()
When it happens
Trigger: Calling open()/register() twice on the same SseEventSource instance, or re-using an already-open source for a new request; manual calls to registerAfterRequest after the source is open.
Common situations: Retrying a failed SSE request by calling open() again on the same source instance instead of creating a new one; caching SseEventSource objects and sharing them across requests; resuming a stream after connection drop without recreating the source.
Related errors
- Services have not been started yet
- OIDC Client Registration is closed
- Registered OIDC Client is closed
- RestClientProxy is closed
- Engine not set
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/b5e831fee01c9893.
Report an issue: GitHub.