{"record":{"id":"df99f343197464ed","repo":"quarkusio/quarkus","slug":"stream-is-closed","errorCode":null,"errorMessage":"Stream is closed","messagePattern":"Stream is closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java","lineNumber":58,"sourceCode":"        write(new byte[] { (byte) b }, 0, 1);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void write(final byte[] b) throws IOException {\n        write(b, 0, b.length);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public void write(final byte[] b, final int off, final int len) throws IOException {\n        if (len < 1) {\n            return;\n        }\n        if (closed) {\n            throw new IOException(\"Stream is closed\");\n        }\n\n        int rem = len;\n        int idx = off;\n        ByteBuf buffer = pooledBuffer;\n        try {\n            if (buffer == null) {\n                pooledBuffer = buffer = allocator.allocateBuffer();\n            }\n            while (rem > 0) {\n                int toWrite = Math.min(rem, buffer.writableBytes());\n                buffer.writeBytes(b, idx, toWrite);\n                rem -= toWrite;\n                idx += toWrite;\n                if (!buffer.isWritable()) {\n                    ByteBuf tmpBuf = buffer;\n                    this.pooledBuffer = buffer = allocator.allocateBuffer();\n                    response.writeBlocking(tmpBuf, false);","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java#L40-L76","documentation":"VertxOutputStream.write(byte[], int, int) throws IOException(\"Stream is closed\") when the response output stream has already been closed and a further write is attempted. After close(), the underlying Vert.x response ends and any additional byte writes are invalid.","triggerScenarios":"Writing to the response OutputStream after close() was called — e.g. StreamingOutput/StreamingResponse continuing to write after an early return closed the stream, a finally block writing a terminator after close, or writing after the request lifecycle ended the response.","commonSituations":"Manual streaming code that ignores close semantics; double flush/close in a finally; frameworks (e.g. SSE or file download handlers) closing the stream while an application filter still writes; exception path that closes the stream then logs the error to the response body.","solutions":["Guard writes with a closed check or restructure so all writes happen before close(); track stream lifetime in one owner class.","Do not write in finally blocks; only clean up resources there.","Catch IOException and treat it as 'client already got the response / stream done' instead of propagating.","Ensure only one component (the framework or your code, not both) closes the stream."],"exampleFix":"// before\nstream.close();\nstream.write(finishBytes); // IOException: Stream is closed\n\n// after\nstream.write(finishBytes);\nstream.close();","handlingStrategy":"validation","validationCode":"private void safeWrite(OutputStream out, byte[] data) throws IOException {\n    if (out == null || !(out instanceof io.quarkus.resteasy.runtime.standalone.VertxOutputStream v) || vIsClosed(v)) {\n        return;\n    }\n    out.write(data);\n}","typeGuard":"boolean isStreamOpen(java.io.OutputStream out) {\n    try {\n        out.flush();\n        return true;\n    } catch (IOException e) {\n        return !\"Stream is closed\".equals(e.getMessage());\n    }\n}","tryCatchPattern":"try {\n    out.write(chunk);\n} catch (IOException e) {\n    if (\"Stream is closed\".equals(e.getMessage())) {\n        LOG.debug(\"Stream already closed; dropping trailing write\");\n        return;\n    }\n    throw e;\n}","preventionTips":["Perform all writes before close(); single owner for stream lifecycle.","Never write from finally blocks.","Guard streaming loops with a volatile 'closed' flag set in close().","Avoid writing error bodies after the stream was closed on an exception path."],"tags":["io","stream","response","lifecycle"],"backgroundTag":"stream-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"}