{"record":{"id":"e45e4ced964479b2","repo":"quarkusio/quarkus","slug":"broadcaster-has-been-closed","errorCode":null,"errorMessage":"Broadcaster has been closed","messagePattern":"Broadcaster has been closed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java","lineNumber":146,"sourceCode":"        onErrorConsumers.forEach(consumer -> {\n            consumer.accept(eventSink, throwable);\n        });\n    }\n\n    private void notifyOnCloseListeners(SseEventSink eventSink) {\n        // First remove the eventSink from the outputQueue to ensure that\n        // concurrent calls to this method will notify listeners only once for a\n        // given eventSink instance.\n        if (outputQueue.remove(eventSink)) {\n            closeConsumers.forEach(consumer -> {\n                consumer.accept(eventSink);\n            });\n        }\n    }\n\n    private void checkClosed() {\n        if (closed.get()) {\n            throw new IllegalStateException(\"Broadcaster has been closed\");\n        }\n    }\n\n    @Override\n    public synchronized void close() {\n        close(true);\n    }\n\n    @Override\n    public synchronized void close(final boolean cascading) {\n        if (!closed.compareAndSet(false, true)) {\n            return;\n        }\n        if (cascading) {\n            writeLock.lock();\n            try {\n                //Javadoc says close the broadcaster and all subscribed {@link SseEventSink} instances.\n                //is it necessary to close the subscribed SseEventSink ?","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java#L128-L164","documentation":"SseBroadcasterImpl.checkClosed() throws IllegalStateException when any broadcaster operation is attempted after close() was called. Once closed, the broadcaster no longer accepts registration, broadcast, onError, or onClose callbacks.","triggerScenarios":"Calling register(), broadcast(), onError(handler), or onClose(handler) on an SseBroadcaster after close(); often when a request completes and closes the broadcaster while another thread still holds a reference.","commonSituations":"Long-lived broadcaster field closed on one request completion and reused by another; asynchronous task broadcasting after the connection shut down; forgetting to recreate the broadcaster per resource instance.","solutions":["Track broadcaster lifecycle and create a new SseBroadcaster after close() if reuse is needed.","Check closed state before broadcasting (guard with a flag or synchronize around close/broadcast).","Move close() to application shutdown (or @PreDestroy) instead of per-request completion if reuse is intended.","Catch IllegalStateException around broadcast calls and reinitialize the broadcaster."],"exampleFix":"// before\nbroadcaster.close(); // on one request end\n... // later, other request\nbroadcaster.broadcast(event); // IllegalStateException\n// after\nif (!broadcasterClosed) {\n    broadcaster.broadcast(event);\n}","handlingStrategy":"try-catch","validationCode":"if (broadcasterClosed.get()) {\n    broadcaster = sse.newBroadcaster();\n    broadcasterClosed.set(false);\n}","typeGuard":null,"tryCatchPattern":"try {\n    broadcaster.broadcast(event);\n} catch (IllegalStateException e) {\n    broadcaster = sse.newBroadcaster(); // recreate after close\n}","preventionTips":["Close broadcasters only at application shutdown if shared","Recreate the broadcaster after close instead of reusing","Synchronize close/broadcast on a shared monitor","Handle reconnects by registering on a fresh broadcaster"],"tags":["jaxrs","sse","resteasy-reactive","illegal-state"],"backgroundTag":"sse-broadcaster-closed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}