{"record":{"id":"7117083e3d4f4cce","repo":"valyala/fasthttp","slug":"cannot-read-q-char-at-the-end-of-chunk-size-w","errorCode":null,"errorMessage":"cannot read %q char at the end of chunk size: %w","messagePattern":"cannot read %q char at the end of chunk size: %w","errorType":"exception","errorClass":"ErrBrokenChunk","httpStatus":null,"severity":"error","filePath":"http.go","lineNumber":3030,"sourceCode":"\t\tdefault:\n\t\t\treturn -1, ErrBrokenChunk{\n\t\t\t\terror: fmt.Errorf(\"invalid character %q after chunk size\", c),\n\t\t\t}\n\t\t}\n\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//","sourceCodeStart":3012,"sourceCodeEnd":3048,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/http.go#L3012-L3048","documentation":"readCrLf verifies the CRLF that terminates a chunk-size line byte by byte. This ErrBrokenChunk is returned when the read of the expected byte ('\\r' or '\\n') fails at the I/O level — the connection was closed, reset, or timed out before the chunk line's terminator arrived.","triggerScenarios":"Peer disconnects or the connection errors while fasthttp reads the CRLF after a chunk size (or between chunks); proxies truncating the stream; read timeout firing mid-line.","commonSituations":"Mobile clients dropping mid-upload; upstream servers killed mid-response; aggressive idle-timeout proxies; network failures during large chunked transfers.","solutions":["Inspect the wrapped cause via errors.As on ErrBrokenChunk; treat it as a connection-level failure, not a data-format issue.","Add client-side retry for idempotent requests and resumable uploads to survive disconnects.","Adjust proxy/load-balancer timeouts so long chunked transfers aren't cut off.","Verify the sender terminates every chunk line with CRLF before closing the connection."],"exampleFix":"// before\nif err := client.Do(req, resp); err != nil { log.Print(err) }\n// after\nif err := client.Do(req, resp); err != nil {\n    var bc fasthttp.ErrBrokenChunk\n    if errors.As(err, &bc) {\n        log.Printf(\"peer sent broken chunked body: %v\", bc.error)\n    }\n    return retryOrFail(err) // retry idempotent ops\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isChunkReadFailure(err error) bool {\n    var bc fasthttp.ErrBrokenChunk\n    if !errors.As(err, &bc) { return false }\n    return errors.Is(bc.error, io.EOF) || errors.Is(bc.error, io.ErrUnexpectedEOF) || errors.Is(bc.error, syscall.ECONNRESET)\n}","tryCatchPattern":"err := client.DoTimeout(req, resp, timeout)\nvar bc fasthttp.ErrBrokenChunk\nif errors.As(err, &bc) {\n    if isRetryable(req) {\n        return retry(req, resp) // idempotent request: retry once\n    }\n    return err\n}","preventionTips":["Retry idempotent requests when chunked reads fail at the I/O level.","Tune proxy/LB idle and response timeouts above the slowest expected transfers.","Use resumable uploads for large chunked bodies from unreliable clients.","Alert on spikes: frequent occurrences indicate disconnecting clients or truncating proxies."],"tags":["fasthttp","chunked-encoding","connection-reset","truncated-body"],"backgroundTag":"broken-chunked-body","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}