{"record":{"id":"dc9d5cf5824c9eb3","repo":"jhy/jsoup","slug":"cannot-follow-redirect-with-a-streamed-request-bod","errorCode":null,"errorMessage":"Cannot follow redirect with a streamed request body; disable followRedirects and resend with a fresh stream","messagePattern":"Cannot follow redirect with a streamed request body; disable followRedirects and resend with a fresh stream","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/jsoup/helper/HttpConnection.java","lineNumber":931,"sourceCode":"            if (!supportsBody)\n                Validate.isFalse(hasBody, \"Cannot set a request body for HTTP method \" + req.method());\n\n            // set up the request for execution\n            if (!req.data().isEmpty() && (!supportsBody || hasBody))\n                serialiseRequestUrl(req);\n            else if (supportsBody)\n                setOutputContentType(req);\n\n            long startTime = System.nanoTime();\n            RequestExecutor executor = RequestDispatch.get(req, prevRes);\n            Response res = null;\n            try {\n                res = executor.execute();\n\n                Method nextMethod = redirectMethod(res.statusCode, req.method());\n                if (nextMethod != null && res.hasHeader(LOCATION) && req.followRedirects()) {\n                    if (nextMethod == req.method() && (req.body instanceof InputStream || needsMultipart(req)))\n                        throw new IOException(\"Cannot follow redirect with a streamed request body; disable followRedirects and resend with a fresh stream\");\n\n                    if (nextMethod != req.method()) {\n                        req.method(nextMethod);\n                        req.data().clear();\n                        req.requestBody(null);\n                        for (String header : REDIRECT_CONTENT_HEADERS)\n                            req.removeHeader(header);\n                    }\n\n                    String location = res.header(LOCATION);\n                    Validate.notNull(location);\n                    URL redir = StringUtil.resolve(req.url(), location);\n                    if (!sameOrigin(req.url(), redir)) {\n                        // remove sensitive headers; defense-in-depth against open redirects\n                        req.removeHeader(\"Authorization\");\n                        req.removeHeader(\"Cookie\");\n                        req.removeHeader(\"Cookie2\");\n                        req.cookies().clear();","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/jhy/jsoup/blob/9851ac5d9c576c6888910b5a51a2362bbc978959/src/main/java/org/jsoup/helper/HttpConnection.java#L913-L949","documentation":"When followRedirects is enabled and a redirect arrives, jsoup cannot replay a request whose body is a live InputStream (or a multipart upload), since the stream has already been consumed. It throws IOException telling you to disable redirects and send the body again yourself with a fresh stream.","triggerScenarios":"Executing a POST/PUT whose body was set via requestBody(InputStream) or via data requiring multipart, with followRedirects(true) (the default), and the server replies 301/302/307/308 keeping the same method.","commonSituations":"File-upload endpoints behind redirects; APIs moved to new hosts returning 307; retry logic resuming an upload session where the first request redirects.","solutions":["Disable redirects: request.followRedirects(false), catch the redirect response, then resend manually with a fresh InputStream","Buffer the body as a byte[] (requestBody(byte[]) or requestBody(String)) so it can be replayed across redirects","If the redirect should change to GET (302/303), ensure the server responds with a method-changing status so the body is dropped"],"exampleFix":"// before\nConnection.Response res = Jsoup.connect(url)\n    .requestBody(new FileInputStream(file))\n    .execute(); // throws on redirect\n// after\nConnection conn = Jsoup.connect(url)\n    .requestBody(new FileInputStream(file))\n    .followRedirects(false);\nConnection.Response res = conn.execute();\nif (res.statusCode() / 100 == 3) {\n    res = Jsoup.connect(res.header(\"Location\"))\n        .requestBody(new FileInputStream(file)) // fresh stream\n        .execute();\n}","handlingStrategy":"try-catch","validationCode":"boolean risky = req.requestBody() instanceof InputStream || usesMultipart(req); if (risky && req.followRedirects()) { /* restructure: disable redirects */ }","typeGuard":null,"tryCatchPattern":"try { res = conn.execute(); } catch (IOException e) { if (e.getMessage().contains(\"streamed request body\")) { /* resend manually with fresh stream */ } }","preventionTips":["Disable followRedirects for upload/stream-body requests","Prefer byte[]/String bodies for POSTs that may be redirected","Write upload helpers that detect 3xx and replay with a fresh InputStream"],"tags":["java","jsoup","http","redirect","request-body"],"backgroundTag":"http-error-response","analyzedSha":"9851ac5d9c576c6888910b5a51a2362bbc978959","analyzedAt":"2026-09-08T15:22:04.931Z","contentChangedAt":"2026-09-08T15:22:04.931Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}