{"id":"ec4ac6a50c92c701","repo":"actix/actix-web","slug":"invalid-chunk-end-cr","errorCode":null,"errorMessage":"Invalid chunk end CR","messagePattern":"Invalid chunk end CR","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"actix-http/src/h1/chunked.rs","lineNumber":172,"sourceCode":"            _ => 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(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk end CR\",\n            ))),\n        }\n    }\n    fn read_end_lf(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\n' => Poll::Ready(Ok(ChunkedState::End)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk end LF\",\n            ))),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-http/src/h1/chunked.rs#L154-L190","documentation":"io::Error(InvalidInput, \"Invalid chunk end CR\") (chunked.rs:172-175) is returned by read_end_cr after a zero-sized terminating chunk ('0' CRLF) when the next byte is not a CR. The chunked encoding trailer sequence is '0' CRLF *(trailer-field) CRLF; this state expects the final CR that closes the message.","triggerScenarios":"After the '0\\r\\n' last-chunk, the peer sends something other than CR to begin the final empty line, e.g. '0\\r\\nX'. read_size_lf transitioned to EndCr (size==0) and read_end_cr sees 'X'.","commonSituations":"A chunked body that omits the final CRLF terminator, or a proxy truncating the stream before the trailer.","solutions":["Ensure the chunked body ends with '0\\r\\n\\r\\n' (last-chunk plus empty trailer line).","Check that the client is not closing the connection before flushing the trailer.","Verify intermediaries pass the trailer through unchanged."],"exampleFix":"// before: missing final terminator\nb\"4\\r\\ndata\\r\\n0\\r\\n\"\n\n// after: complete trailer\nb\"4\\r\\ndata\\r\\n0\\r\\n\\r\\n\"","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Missing final trailer CR -> bad request / incomplete body.\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":["Ensure chunked bodies end with '0\\r\\n\\r\\n'.","Confirm the client flushes the trailer before closing the socket.","Check proxies forward trailers unchanged."],"tags":["http","transfer-encoding","chunked","actix-http","protocol"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}