{"record":{"id":"7240fa01b3986d15","repo":"quarkusio/quarkus","slug":"connection-has-been-closed-7240fa","errorCode":null,"errorMessage":"Connection has been closed","messagePattern":"Connection has been closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"independent-projects/vertx-utils/src/main/java/io/quarkus/vertx/utils/VertxOutputStream.java","lineNumber":128,"sourceCode":"            throw new IOException(\"Failed to write\", e);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private void awaitWriteable() throws IOException {\n        // is it running in an event loop?\n        if (Context.isOnEventLoopThread()) {\n            // NEVER block the event loop!\n            return;\n        }\n        assert lock.isHeldByCurrentThread();\n        while (response.writeQueueFull()) {\n            if (throwable != null) {\n                throw new IOException(throwable);\n            }\n            if (response.closed()) {\n                throw new IOException(\"Connection has been closed\");\n            }\n            try {\n                waitingForDrain = true;\n                // To make sure we don't get stuck waiting, we time out periodically\n                drainCondition.await(1, TimeUnit.SECONDS);\n                // Check for timeout / closed connection\n                if (request.response().ended() || request.response().closed()) {\n                    if (throwable != null) {\n                        // We had an exception, propagate it\n                        throw new IOException(throwable);\n                    } else {\n                        throw new IOException(\"Connection has been closed\");\n                    }\n                }\n            } catch (InterruptedException e) {\n                throw new InterruptedIOException(e.getMessage());\n            } finally {\n                waitingForDrain = false;","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/vertx-utils/src/main/java/io/quarkus/vertx/utils/VertxOutputStream.java#L110-L146","documentation":"While waiting for the response write queue to drain, awaitWriteable() checks response.closed(); if Vertx reports the response/connection has closed, it throws IOException('Connection has been closed') because the queued data can never be delivered. This prevents blocking indefinitely on a drain event that will never arrive.","triggerScenarios":"write() is called, the write queue is full, and the peer closes the TCP connection (or the response is closed server-side) before the queue drains.","commonSituations":"User cancels a download; mobile clients switching networks mid-stream; reverse proxy closing upstream connections after idle timeout; server-side timeouts (e.g. quarkus.http.idle-timeout) firing during a slow stream.","solutions":["Treat this as a normal client-disconnect signal: catch it, release resources, and stop producing data","Tune server idle/timeouts if legitimate slow clients are being cut off","Write smaller chunks more frequently so the queue drains between writes","Add a drain/close handler on the response to abort generation work early"],"exampleFix":"// before\nwhile (hasMore()) {\n    out.write(nextChunk()); // throws once client disconnects\n}\n// after\ntry {\n    while (hasMore() && !response.closed()) {\n        out.write(nextChunk());\n    }\n} catch (IOException closed) {\n    cancelGeneration();\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    out.writeBlocking(chunk);\n} catch (IOException e) {\n    if (e.getCause() != null) {\n        logger.warn(\"Connection failure during stream: {}\", e.getCause().getMessage());\n    }\n    cleanup();\n}","preventionTips":["Detect client disconnects early (response.closeHandler) and cancel generation","Don't end the response from another thread while streaming is in progress","Set realistic quarkus.http.idle-timeout values for long streams"],"tags":["io","vertx","connection","streaming"],"backgroundTag":"connection-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"}