{"record":{"id":"87a3fda4120afd8d","repo":"valyala/fasthttp","slug":"fasthttp-cannot-follow-a-body-preserving-redirect","errorCode":null,"errorMessage":"fasthttp: cannot follow a body-preserving redirect for a request with a body stream","messagePattern":"fasthttp: cannot follow a body-preserving redirect for a request with a body stream","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":1230,"sourceCode":"\t\t}\n\t}\n\n\tstatusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)\n\n\treturn statusCode, body, err\n}\n\nvar (\n\t// ErrMissingLocation is returned by clients when the Location header is missing on\n\t// an HTTP response with a redirect status code.\n\tErrMissingLocation = errors.New(\"fasthttp: missing location header for http redirect\")\n\t// ErrTooManyRedirects is returned by clients when the number of redirects followed\n\t// exceed the max count.\n\tErrTooManyRedirects = errors.New(\"fasthttp: too many redirects detected when doing the request\")\n\t// ErrRedirectBodyStream is returned by clients when a redirect that keeps the request\n\t// body is received for a request whose body is a stream. The hop that produced the\n\t// redirect consumed the stream, so the body cannot be sent again.\n\tErrRedirectBodyStream = errors.New(\"fasthttp: cannot follow a body-preserving redirect for a request with a body stream\")\n\n\t// ErrHostClientRedirectToDifferentScheme is returned when a HostClient follows a redirect to a different protocol.\n\tErrHostClientRedirectToDifferentScheme = errors.New(\"fasthttp: hostclient can't follow redirects to a different protocol,\" +\n\t\t\" please use client instead\")\n)\n\nconst defaultMaxRedirectsCount = 16\n\n// Only drain response streams that are known to be small. Reading an unknown\n// length stream can block forever (for example, on an event stream), while\n// closing a large stream avoids transferring a body the caller discarded.\nconst maxResponseBodyDrainSize = 8 * 1024\n\nfunc closeOrDrainResponseBody(resp *Response, maxDrainSize int) error {\n\tif !resp.IsBodyStream() {\n\t\treturn nil\n\t}\n","sourceCodeStart":1212,"sourceCodeEnd":1248,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/client.go#L1212-L1248","documentation":"ErrRedirectBodyStream is returned when a body-preserving redirect (e.g. 307/308) is received for a request whose body was set as a stream. The hop that produced the redirect already consumed the stream, so the body cannot be replayed on the redirect target.","triggerScenarios":"Using Request.SetBodyStream with a non-replayable reader and issuing the request via a redirect-following client; the server answers with a redirect that must re-send the body.","commonSituations":"Uploading from an io.Reader (file/pipe) to an endpoint behind auth that redirects to a CDN or presigned URL; POST bodies streamed to services responding 307/308.","solutions":["Buffer the body first (SetBody / read the stream into memory) so it can be replayed across the redirect","Re-create the stream (e.g. re-open the file) and re-issue the request after the redirect","Avoid redirect-following for streaming uploads: issue requests manually and handle 3xx yourself","Point the request directly at the final URL to skip the redirecting hop"],"exampleFix":"// before\nreq.SetBodyStream(file, -1) // consumed on first hop; 307 redirect fails\n// after\ndata, _ := io.ReadAll(file)\nreq.SetBody(data) // replayable across redirects","handlingStrategy":"validation","validationCode":"// Only stream bodies when redirects cannot require a replay\nif req.IsBodyStream() {\n    // buffer the body or use a redirect-unaware request path\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, fasthttp.ErrRedirectBodyStream) {\n    // re-open the source reader and resend with a buffered body\n}","preventionTips":["Prefer SetBody/SetBodyRaw for requests that may redirect","Re-open files/pipes and retry when a redirect is possible","Disable redirect-following for streaming uploads","Target the final (post-redirect) URL directly"],"tags":["http","redirect","streaming","request-body"],"backgroundTag":"body-stream-redirect","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}