valyala/fasthttp · error · ErrBrokenChunk

cannot read '\r' char at the end of chunk size: %w

Error message

cannot read '\r' char at the end of chunk size: %w

What it means

fasthttp wraps parse failures of a chunked (Transfer-Encoding: chunked) body in ErrBrokenChunk. This variant fires when reading the CR that must terminate the chunk-size line fails at the I/O level — the connection ended or errored before the '\r' byte could be read. The wrapped cause (io.ErrUnexpectedEOF, connection reset, timeout) is inside ErrBrokenChunk.error.

Source

Thrown at http.go:2979

				error: errors.New("cannot find crlf at the end of chunk"),
			}
		}
		dst = dst[:len(dst)-strCRLFLen]
	}
}

func parseChunkSize(r *bufio.Reader) (int, error) {
	n, err := readHexInt(r)
	if err != nil {
		return -1, err
	}
	inExt := false
	afterSizeOWS := false
	for {
		c, err := r.ReadByte()
		if err != nil {
			return -1, ErrBrokenChunk{
				error: fmt.Errorf("cannot read '\\r' char at the end of chunk size: %w", err),
			}
		}
		if c == '\r' {
			if err := r.UnreadByte(); err != nil {
				return -1, ErrBrokenChunk{
					error: fmt.Errorf("cannot unread '\\r' char at the end of chunk size: %w", err),
				}
			}
			break
		}
		// Security: Don't allow newlines in chunk extensions.
		// This can lead to request smuggling issues with some reverse proxies.
		if c == '\n' {
			return -1, ErrBrokenChunk{
				error: errors.New("invalid character '\\n' after chunk size"),
			}
		}
		if inExt {

View on GitHub (pinned to c96f600972)

Solutions

  1. Handle ErrBrokenChunk via errors.As and inspect the wrapped cause; treat it as a truncated chunked body from the peer.
  2. Fix the client/proxy that closes the connection before finishing the chunked transfer.
  3. Verify the peer speaks correct chunked encoding (each size line ends with CRLF).
  4. Set/raise read timeouts so slow peers aren't cut off mid-line, and add retry logic for idempotent requests.

Example fix

// before
body, err := ctx.Request.Body()
if err != nil { return err }
// after
body, err := ctx.Request.Body()
var bc fasthttp.ErrBrokenChunk
if errors.As(err, &bc) {
    ctx.Logger().Printf("broken chunked body from %s: %v", ctx.RemoteAddr(), bc.error)
    return // drop malformed request
}
Defensive patterns

Strategy: try-catch

Type guard

func isBrokenChunk(err error) bool {
    var bc fasthttp.ErrBrokenChunk
    return errors.As(err, &bc)
}

Try / catch

var bc fasthttp.ErrBrokenChunk
if errors.As(err, &bc) {
    log.Printf("broken chunked body (read failed): %v", bc.error)
    // connection state is unusable: close it
    ctx.ConnectionClose()
}

Prevention

When it happens

Trigger: Server or client parsing a chunked body when the peer closes or resets the connection mid-chunk-size-line, before sending the trailing CRLF; also triggered by proxies that truncate responses.

Common situations: Client disconnects mid-request on a server; upstream proxy/load balancer cuts the response; flaky network dropping the tail of the body; clients sending malformed chunked framing.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/36fb97bca186bb89. Report an issue: GitHub.