valyala/fasthttp · error
cannot gunzip request body: %w
Error message
cannot gunzip request body: %w
What it means
When reading the request body (Request.Body/StreamBody path), fasthttp transparently decompresses a body whose Content-Encoding is gzip via gzip.NewReader. If the gzip stream is corrupt or truncated, the reader construction fails and the error is wrapped as 'cannot gunzip request body'. Any other non-empty Content-Encoding is rejected as unsupported.
Source
Thrown at http.go:1164
func (req *Request) MultipartFormWithLimit(maxBodySize int) (*multipart.Form, error) {
if req.multipartForm != nil {
return req.multipartForm, nil
}
req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
if req.multipartFormBoundary == "" {
return nil, ErrNoMultipartForm
}
var err error
ce := req.Header.peek(strContentEncoding)
if req.bodyStream != nil {
bodyStream := req.bodyStream
var lr *io.LimitedReader
if bytes.Equal(ce, strGzip) {
if bodyStream, err = gzip.NewReader(bodyStream); err != nil {
return nil, fmt.Errorf("cannot gunzip request body: %w", err)
}
} else if len(ce) > 0 {
return nil, fmt.Errorf("unsupported content-encoding: %q", ce)
}
if maxBodySize > 0 {
lr = &io.LimitedReader{
R: bodyStream,
N: int64(maxBodySize) + 1,
}
bodyStream = lr
}
mr := multipart.NewReader(bodyStream, req.multipartFormBoundary)
req.multipartForm, err = mr.ReadForm(8 * 1024)
if err != nil {
if lr != nil && lr.N <= 0 {
return nil, fmt.Errorf("cannot read multipart/form-data body: %w", ErrBodyTooLarge)
}View on GitHub (pinned to c96f600972)
Solutions
- Verify the client actually gzips the body (gzip.Writer with Close/Flush called before send).
- Remove Content-Encoding: gzip if the body is plain, or switch to the encoding fasthttp supports.
- If you need deflate/brotli, handle decompression manually: read the raw body stream yourself instead of relying on auto-gunzip.
- Check for proxies that re-compress or truncate the body in transit.
Example fix
// before (body not actually gzip)
req.Header.Set("Content-Encoding", "gzip")
req.SetBodyString("hello")
// after
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
gz.Write([]byte("hello"))
gz.Close()
req.Header.Set("Content-Encoding", "gzip")
req.SetBodyRaw(buf.Bytes()) Defensive patterns
Strategy: try-catch
Validate before calling
func isRealGzip(body []byte) bool {
return len(body) > 2 && body[0] == 0x1f && body[1] == 0x8b
} // only set Content-Encoding: gzip if this passes Try / catch
body, err := req.Body() // or StreamBody
if err != nil {
var gze *gzip.HeaderError
if strings.Contains(err.Error(), "cannot gunzip request body") || errors.As(err, &gze) {
// read raw body instead: req.BodyRaw(), or respond 400
}
} Prevention
- Always Close()/Flush() gzip.Writer before sending the body
- Only set Content-Encoding when the body really is compressed
- Avoid double compression through chained proxies
- Prefer no Content-Encoding unless both ends agree on gzip
When it happens
Trigger: Client sends 'Content-Encoding: gzip' but the body is not valid gzip data (plain text, partially sent, or doubly-compressed), or uses an unsupported encoding like deflate/br.
Common situations: Clients gzipping bodies with broken streaming code; double compression through a proxy; test scripts sending fake gzip; clients using brotli/deflate expecting server support.
Related errors
- fasthttp: unsupported content-encoding
- fasthttp: contain forbidden trailer
- fasthttp: error when reading response headers
- fasthttp: error when reading response trailer
- fasthttp: cannot find whitespace in the first line of respon
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/18866f78a4731dfa.
Report an issue: GitHub.