{"id":"b4f995461c9eedce","repo":"actix/actix-web","slug":"invalid-chunk-size-lf","errorCode":null,"errorMessage":"Invalid chunk size LF","messagePattern":"Invalid chunk size LF","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"actix-http/src/h1/chunked.rs","lineNumber":116,"sourceCode":"            ))),\n        }\n    }\n    fn read_extension(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),\n            // strictly 0x20 (space) should be disallowed but we don't parse quoted strings here\n            0x00..=0x08 | 0x0a..=0x1f | 0x7f => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid character in chunk extension\",\n            ))),\n            _ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions\n        }\n    }\n    fn read_size_lf(rdr: &mut BytesMut, size: u64) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr) {\n            b'\\n' if size > 0 => Poll::Ready(Ok(ChunkedState::Body)),\n            b'\\n' if size == 0 => Poll::Ready(Ok(ChunkedState::EndCr)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk size LF\",\n            ))),\n        }\n    }\n\n    fn read_body(\n        rdr: &mut BytesMut,\n        rem: &mut u64,\n        buf: &mut Option<Bytes>,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Chunked read, remaining={:?}\", rem);\n\n        let len = rdr.len() as u64;\n        if len == 0 {\n            Poll::Ready(Ok(ChunkedState::Body))\n        } else {\n            let slice;","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-http/src/h1/chunked.rs#L98-L134","documentation":"io::Error(InvalidInput, \"Invalid chunk size LF\") (chunked.rs:116-119) is returned by read_size_lf when the byte following the chunk size (and optional extension) is not a lone LF after the expected CR. The state machine reaches SizeLf only after consuming a CR; a byte other than '\\n' here breaks the required CRLF terminator.","triggerScenarios":"A chunk size line uses a bare CR without LF, or inserts a character between CR and LF, e.g. '4\\rX\\n'. read_size emits SizeLf on the CR and read_size_lf sees 'X'.","commonSituations":"A non-conformant encoder using lone CR or inserting bytes inside the line terminator; line-ending corruption by a proxy.","solutions":["Ensure every size line ends with a strict CRLF (0x0D 0x0A).","Use Content-Length when the body length is known.","Capture the wire bytes to confirm the terminator is missing."],"exampleFix":"// before\nb\"4\\rX\\ndata\\r\\n0\\r\\n\\r\\n\"\n\n// after\nb\"4\\r\\ndata\\r\\n0\\r\\n\\r\\n\"","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Handle the malformed CRLF as a 400 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":["Always terminate chunk size lines with a strict CRLF (0x0D 0x0A).","Use Content-Length when the body size is known.","Verify proxies are not rewriting line endings."],"tags":["http","transfer-encoding","chunked","actix-http","protocol"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}