{"id":"de359ad1015d0650","repo":"actix/actix-web","slug":"invalid-chunk-body-cr","errorCode":null,"errorMessage":"Invalid chunk body CR","messagePattern":"Invalid chunk body CR","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"actix-http/src/h1/chunked.rs","lineNumber":154,"sourceCode":"                slice = rdr.split().freeze();\n                *rem -= len;\n            } else {\n                slice = rdr.split_to(*rem as usize).freeze();\n                *rem = 0;\n            }\n            *buf = Some(slice);\n            if *rem > 0 {\n                Poll::Ready(Ok(ChunkedState::Body))\n            } else {\n                Poll::Ready(Ok(ChunkedState::BodyCr))\n            }\n        }\n    }\n\n    fn read_body_cr(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::BodyLf)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk body CR\",\n            ))),\n        }\n    }\n    fn read_body_lf(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\n' => Poll::Ready(Ok(ChunkedState::Size)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk body LF\",\n            ))),\n        }\n    }\n    fn read_end_cr(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::EndLf)),\n            _ => Poll::Ready(Err(io::Error::new(","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-http/src/h1/chunked.rs#L136-L172","documentation":"io::Error(InvalidInput, \"Invalid chunk body CR\") (chunked.rs:154-157) is returned by read_body_cr when, after consuming exactly <size> body bytes, the next byte is not a CR. RFC 7230 requires each chunk body be terminated by CRLF; any other byte here is a framing error.","triggerScenarios":"The declared chunk size does not match the actual body length, so the parser reads the 'wrong' bytes as the terminator. e.g. declaring '4' but sending only 3 data bytes leaves the 4th data byte to be checked against CR.","commonSituations":"Encoder miscalculating chunk length, a proxy truncating or re-chunking the body, or a client streaming an incorrect size.","solutions":["Make the peer's declared chunk size exactly equal the number of body bytes that follow.","Verify no intermediary is re-segmenting the body.","Switch to Content-Length if the full size is known up front."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Mismatched chunk length -> bad request.\nuse actix_http::error::PayloadError;\nif matches!(payload.next().await, Some(Err(PayloadError::Io(e))) if e.kind() == io::ErrorKind::InvalidInput) {\n    return HttpResponse::BadRequest().finish();\n}","preventionTips":["Make the declared chunk size exactly equal the number of body bytes that follow.","Avoid re-chunking the body in intermediaries.","Prefer Content-Length for fixed-size payloads."],"tags":["http","transfer-encoding","chunked","actix-http","protocol"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}