valyala/fasthttp · error
fasthttp: cannot follow a body-preserving redirect for a req
Error message
fasthttp: cannot follow a body-preserving redirect for a request with a body stream
What it means
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.
Source
Thrown at client.go:1230
}
}
statusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)
return statusCode, body, err
}
var (
// ErrMissingLocation is returned by clients when the Location header is missing on
// an HTTP response with a redirect status code.
ErrMissingLocation = errors.New("fasthttp: missing location header for http redirect")
// ErrTooManyRedirects is returned by clients when the number of redirects followed
// exceed the max count.
ErrTooManyRedirects = errors.New("fasthttp: too many redirects detected when doing the request")
// ErrRedirectBodyStream is returned by clients when a redirect that keeps the request
// body is received for a request whose body is a stream. The hop that produced the
// redirect consumed the stream, so the body cannot be sent again.
ErrRedirectBodyStream = errors.New("fasthttp: cannot follow a body-preserving redirect for a request with a body stream")
// ErrHostClientRedirectToDifferentScheme is returned when a HostClient follows a redirect to a different protocol.
ErrHostClientRedirectToDifferentScheme = errors.New("fasthttp: hostclient can't follow redirects to a different protocol," +
" please use client instead")
)
const defaultMaxRedirectsCount = 16
// Only drain response streams that are known to be small. Reading an unknown
// length stream can block forever (for example, on an event stream), while
// closing a large stream avoids transferring a body the caller discarded.
const maxResponseBodyDrainSize = 8 * 1024
func closeOrDrainResponseBody(resp *Response, maxDrainSize int) error {
if !resp.IsBodyStream() {
return nil
}
View on GitHub (pinned to c96f600972)
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
Example fix
// before req.SetBodyStream(file, -1) // consumed on first hop; 307 redirect fails // after data, _ := io.ReadAll(file) req.SetBody(data) // replayable across redirects
Defensive patterns
Strategy: validation
Validate before calling
// Only stream bodies when redirects cannot require a replay
if req.IsBodyStream() {
// buffer the body or use a redirect-unaware request path
} Try / catch
if errors.Is(err, fasthttp.ErrRedirectBodyStream) {
// re-open the source reader and resend with a buffered body
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- fasthttp: missing location header for http redirect
- fasthttp: too many redirects detected when doing the request
- fasthttp: hostclient can't follow redirects to a different p
- fasthttp: need more data: cannot find trailing lf
- non-zero body for non-post request
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/87a3fda4120afd8d.
Report an issue: GitHub.