{"record":{"id":"847b9457e6cd352d","repo":"valyala/fasthttp","slug":"unexpected-char-q-at-the-end-of-chunk-size-expec","errorCode":null,"errorMessage":"unexpected char %q at the end of chunk size: expected %q","messagePattern":"unexpected char %q at the end of chunk size: expected %q","errorType":"exception","errorClass":"ErrBrokenChunk","httpStatus":null,"severity":"error","filePath":"http.go","lineNumber":3035,"sourceCode":"\t}\n\terr = readCrLf(r)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\treturn n, nil\n}\n\nfunc readCrLf(r *bufio.Reader) error {\n\tfor _, exp := range []byte{'\\r', '\\n'} {\n\t\tc, err := r.ReadByte()\n\t\tif err != nil {\n\t\t\treturn ErrBrokenChunk{\n\t\t\t\terror: fmt.Errorf(\"cannot read %q char at the end of chunk size: %w\", exp, err),\n\t\t\t}\n\t\t}\n\t\tif c != exp {\n\t\t\treturn ErrBrokenChunk{\n\t\t\t\terror: fmt.Errorf(\"unexpected char %q at the end of chunk size: expected %q\", c, exp),\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// SetTimeout sets timeout for the request.\n//\n// The following code:\n//\n//\treq.SetTimeout(t)\n//\tc.Do(&req, &resp)\n//\n// is equivalent to\n//\n//\tc.DoTimeout(&req, &resp, t)\nfunc (req *Request) SetTimeout(t time.Duration) {\n\treq.timeout = t","sourceCodeStart":3017,"sourceCodeEnd":3053,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/http.go#L3017-L3053","documentation":"In readCrLf, after the chunk size (and optional extension), fasthttp expects exactly '\\r' then '\\n'. If the byte read differs from the expected one it returns ErrBrokenChunk with this message, hardening against malformed chunked framing used in request-smuggling attacks.","triggerScenarios":"Peer sends something other than CRLF to end the chunk-size line — e.g. bare LF (\"5\\n\"), a stray space, or binary noise at that position.","commonSituations":"HTTP/1.0-style or hand-rolled clients using bare LF line endings; lenient proxies normalizing CRLF to LF; fuzzing/scanning traffic; desync between a front proxy and fasthttp.","solutions":["Fix the sender to terminate chunk-size lines with CRLF, not bare LF.","Check front-end proxies/load balancers for CRLF-normalization and disable it for chunked bodies.","Treat the peer as misbehaving: fasthttp returns ErrBrokenChunk; close the connection and log for security review.","If you control the client library, use an HTTP-conforming serializer instead of hand-built chunked output."],"exampleFix":"// before (wire format)\n5\\nhello\\n0\\n\\n\n// after\n5\\r\\nhello\\r\\n0\\r\\n\\r\\n","handlingStrategy":"type-guard","validationCode":"// Client side, verify every chunk-size line ends with CRLF before sending:\nfunc validChunkLineEnd(line []byte) bool {\n    return bytes.HasSuffix(line, []byte(\"\\r\\n\"))\n}","typeGuard":"func isBadCRLF(err error) bool {\n    var bc fasthttp.ErrBrokenChunk\n    return errors.As(err, &bc) &&\n        strings.Contains(bc.error.Error(), \"unexpected char\")\n}","tryCatchPattern":"var bc fasthttp.ErrBrokenChunk\nif errors.As(err, &bc) && strings.Contains(bc.error.Error(), \"unexpected char\") {\n    // peer used bare LF or garbage: close, log source for security review\n    ctx.ConnectionClose()\n}","preventionTips":["Always terminate chunk lines with \\r\\n, never bare \\n.","Disable CRLF-to-LF normalization in edge proxies for chunked bodies.","Flag repeat offenders: this pattern is common in smuggling probes.","Use conforming HTTP client libraries rather than hand-built chunk encoding."],"tags":["fasthttp","chunked-encoding","request-smuggling","http-protocol"],"backgroundTag":"broken-chunked-body","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}