{"record":{"id":"2df890d6800bd2cc","repo":"didi/DoKit","slug":"cannot-write-request-body-after-response-has-been","errorCode":null,"errorMessage":"cannot write request body after response has been read","messagePattern":"cannot write request body after response has been read","errorType":"exception","errorClass":"ProtocolException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java","lineNumber":485,"sourceCode":"                return ConvertUtils.string2InputStream(\"response.body() is null:\" + url.toString(), \"utf-8\");\n            }\n\n        }\n\n        @Override\n        public OutputStream getOutputStream() throws IOException {\n            OutputStreamRequestBody requestBody = (OutputStreamRequestBody) buildCall().request().body();\n            if (requestBody == null) {\n                throw new ProtocolException(\"method does not support a request body: \" + method);\n            }\n\n            if (requestBody instanceof StreamedRequestBody) {\n                connect();\n                networkInterceptor.proceed();\n            }\n\n            if (requestBody.closed) {\n                throw new ProtocolException(\"cannot write request body after response has been read\");\n            }\n\n            return requestBody.outputStream;\n        }\n\n        @Override\n        public Permission getPermission() {\n            URL url = getURL();\n            String hostname = url.getHost();\n            int hostPort = url.getPort() != -1\n                    ? url.getPort()\n                    : HttpUrl.defaultPort(url.getProtocol());\n            if (usingProxy()) {\n                InetSocketAddress proxyAddress = (InetSocketAddress) client.proxy().address();\n                hostname = proxyAddress.getHostName();\n                hostPort = proxyAddress.getPort();\n            }\n            return new SocketPermission(hostname + \":\" + hostPort, \"connect, resolve\");","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java#L467-L503","documentation":"getOutputStream() checks requestBody.closed after optionally proceeding with a streamed request; if the request body was already closed (which happens once the response has been read or the stream closed), writing is rejected with ProtocolException(\"cannot write request body after response has been read\"). This prevents mutating a request that OkHttp has already sent.","triggerScenarios":"Calling getOutputStream() a second time on the same connection after closing the first stream or after reading the response (getInputStream/getResponseCode); writing to a stream obtained before connect() after the response arrived.","commonSituations":"Retry logic that reuses one HttpURLConnection instance; streaming upload code that captures the OutputStream, reads the response, then tries to append more data.","solutions":["Use a fresh HttpURLConnection (url.openConnection()) for each request/retry attempt.","Write the entire body before touching any response API; never call getOutputStream() twice.","Keep a boolean sent flag in wrapper code to prevent post-response writes."],"exampleFix":"// before\nOutputStream os = conn.getOutputStream();\nos.write(part1); os.close();\nString body = read(conn.getInputStream());\nconn.getOutputStream().write(part2); // ProtocolException\n\n// after\n// send part1+part2 in one go, or open a new connection:\nHttpURLConnection conn2 = (HttpURLConnection) url.openConnection();","handlingStrategy":"validation","validationCode":"if (bodyWritten) throw new IllegalStateException(\"request already sent\"); // own guard before writes","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One connection, one request: never reuse a HttpURLConnection for a second attempt.","Finish all body writes before calling any response-reading API."],"tags":["network","http","urlconnection","request-body","state-machine"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}