{"id":"a04d8940d04be671","repo":"hyperium/hyper","slug":"invalid-chunk-size-lf","errorCode":null,"errorMessage":"Invalid chunk size LF","messagePattern":"Invalid chunk size LF","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src/proto/h1/decode.rs","lineNumber":469,"sourceCode":"            } // no supported extensions\n        }\n    }\n    fn read_size_lf<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        size: u64,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Chunk size is {:?}\", size);\n        match byte!(rdr, cx) {\n            b'\\n' => {\n                if size == 0 {\n                    Poll::Ready(Ok(ChunkedState::EndCr))\n                } else {\n                    debug!(\"incoming chunked header: {0:#X} ({0} bytes)\", size);\n                    Poll::Ready(Ok(ChunkedState::Body))\n                }\n            }\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk size LF\",\n            ))),\n        }\n    }\n\n    fn read_body<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        rem: &mut u64,\n        buf: &mut Option<Bytes>,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Chunked read, remaining={:?}\", rem);\n\n        // cap remaining bytes at the max capacity of usize\n        let to_read = usize::try_from(*rem).unwrap_or(usize::MAX);\n        let slice = ready!(rdr.read_mem(cx, to_read))?;\n        let count = slice.len();","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/proto/h1/decode.rs#L451-L487","documentation":"Thrown in read_size_lf (src/proto/h1/decode.rs:469) after the decoder saw '\\r' ending the chunk-size line and expects the following '\\n'. Any byte other than '\\n' yields io::ErrorKind::InvalidInput, meaning the size line's CRLF terminator was malformed (a CR not followed by LF).","triggerScenarios":"A chunk-size line ending in CR but not LF, e.g. \"F\\rF\" (CR followed by 'F'), or a sender that writes \"\\r\" alone and then data with no LF.","commonSituations":"A peer or middleware that strips/converts LF; a transport that drops the LF byte; copy-paste of chunk examples that used a bare CR.","solutions":["Confirm the size line is terminated by a true CRLF (\\r\\n), not a lone CR.","Audit any middleware that transforms newlines in the response body.","Re-emit framing with write!(w, \"{:x}\\r\\n\", len) so both bytes are always written."],"exampleFix":"// before: only CR written\nwrite!(w, \"{:x}\\r\", len).await?; // -> error 25\n\n// after: full CRLF\nwrite!(w, \"{:x}\\r\\n\", len).await?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Some(Err(e)) => {\n    let kind = e.source()\n        .and_then(|s| s.downcast_ref::<std::io::Error>())\n        .map(|io| io.kind());\n    if matches!(kind, Some(std::io::ErrorKind::InvalidInput)) {\n        tracing::warn!(error=%e, \"chunk size line CR not followed by LF\");\n        break;\n    }\n    return Err(e.into());\n}","preventionTips":["Always write the size-line terminator as the literal \"\\r\\n\", never a lone \"\\r\".","Disable body newline transcoding in upstream proxies.","Write framing bytes from a single buffer to avoid splitting CR from LF across writes."],"tags":["http","http1","chunked","framing","hyper","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}