{"record":{"id":"55bc1e7a81ce946d","repo":"didi/DoKit","slug":"closed-55bc1e","errorCode":null,"errorMessage":"closed","messagePattern":"closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java","lineNumber":833,"sourceCode":"        boolean closed;\n\n        void initOutputStream(final BufferedSink sink, final long expectedContentLength) {\n            this.timeout = sink.timeout();\n            this.expectedContentLength = expectedContentLength;\n\n            // An output stream that writes to sink. If expectedContentLength is not -1, then this expects\n            // exactly that many bytes to be written.\n            this.outputStream = new OutputStream() {\n                private long bytesReceived;\n\n                @Override\n                public void write(int b) throws IOException {\n                    write(new byte[]{(byte) b}, 0, 1);\n                }\n\n                @Override\n                public void write(byte[] source, int offset, int byteCount) throws IOException {\n                    if (closed) throw new IOException(\"closed\"); // Not IllegalStateException!\n\n                    if (expectedContentLength != -1L && bytesReceived + byteCount > expectedContentLength) {\n                        throw new ProtocolException(\"expected \" + expectedContentLength\n                                + \" bytes but received \" + bytesReceived + byteCount);\n                    }\n\n                    bytesReceived += byteCount;\n                    try {\n                        sink.write(source, offset, byteCount);\n                    } catch (InterruptedIOException e) {\n                        throw new SocketTimeoutException(e.getMessage());\n                    }\n                }\n\n                @Override\n                public void flush() throws IOException {\n                    if (closed) return; // Weird, but consistent with historical behavior.\n                    sink.flush();","sourceCodeStart":815,"sourceCodeEnd":851,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java#L815-L851","documentation":"The OutputStreamRequestBody's anonymous OutputStream throws IOException(\"closed\") (deliberately IOException, not IllegalStateException, to match OkHttp's semantics) when write() is called after close(). Writing to an already-closed request-body stream corrupts accounting of bytes sent, so it is rejected.","triggerScenarios":"Calling write()/flush-with-write on the stream obtained from getOutputStream() after close() was called on it; a second flush after close that actually writes; writing in a finally block after the stream was closed on an error path.","commonSituations":"Multipart writers or serializers that close the stream in a helper and then write a trailing boundary; error-path cleanup code that still attempts a final write; wrappers that close and then retry on the same stream.","solutions":["Track stream state (boolean closed) in your writer and skip writes after close.","Ensure only one component owns close(); write the complete body (including multipart trailing boundary) before closing.","Move cleanup writes out of finally blocks; close() should be the last operation."],"exampleFix":"// before\nos.write(payload);\nos.close();\nos.write(trailer); // IOException: closed\n\n// after\nos.write(payload);\nos.write(trailer);\nos.close();","handlingStrategy":"try-catch","validationCode":"boolean streamClosed = false;\n// your writer checks: if (streamClosed) return; before each write","typeGuard":null,"tryCatchPattern":"try { os.write(chunk); } catch (IOException e) { if (\"closed\".equals(e.getMessage())) { /* logic bug: writing after close */ throw new IllegalStateException(\"body already closed\", e); } throw e; }","preventionTips":["Single owner for close(): write everything, then close, never write again.","Avoid writes in finally blocks and avoid double-closing helpers."],"tags":["network","http","io","stream","request-body"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}