{"id":"958d537ff3ff5e2f","repo":"hyperium/hyper","slug":"unexpected-eof-during-chunk-size-line","errorCode":null,"errorMessage":"unexpected EOF during chunk size line","messagePattern":"unexpected EOF during chunk size line","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src/proto/h1/decode.rs","lineNumber":258,"sourceCode":"    #[cfg(test)]\n    async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Frame<Bytes>, io::Error> {\n        futures_util::future::poll_fn(move |cx| self.decode(cx, body)).await\n    }\n}\n\nimpl fmt::Debug for Decoder {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(&self.kind, f)\n    }\n}\n\nmacro_rules! byte (\n    ($rdr:ident, $cx:expr) => ({\n        let buf = ready!($rdr.read_mem($cx, 1))?;\n        if !buf.is_empty() {\n            buf[0]\n        } else {\n            return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof,\n                                      \"unexpected EOF during chunk size line\")));\n        }\n    })\n);\n\nmacro_rules! or_overflow {\n    ($e:expr) => (\n        match $e {\n            Some(val) => val,\n            None => return Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid chunk size: overflow\",\n            ))),\n        }\n    )\n}\n\nmacro_rules! put_u8 {","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/proto/h1/decode.rs#L240-L276","documentation":"Thrown in the HTTP/1 chunked decoder via the byte! macro (src/proto/h1/decode.rs:258) as io::Error::new(UnexpectedEof, \"unexpected EOF during chunk size line\"). It fires when the connection EOFs while the parser is still reading the hex chunk-size line of a Transfer-Encoding: chunked body — i.e. the chunked stream was truncated before the next size token was complete.","triggerScenarios":"The byte! macro (decode.rs:252-262) calls read_mem(1) and gets an empty buffer (EOF) while in Size/SizeLws/Extension/SizeLf/BodyCr/BodyLf/Trailer states — i.e. anywhere a chunk framing byte is expected. Happens when the peer closes the connection between chunks instead of sending the terminating 0-size chunk.","commonSituations":"A chunked response is cut off before the final '0\\r\\n\\r\\n'; a streaming producer crashes mid-chunk; a proxy times out and drops a chunked body; network reset between chunks. The decoder reached the end of stream before it saw the chunk-size digits it needed.","solutions":["Confirm the peer sends the full chunked body including the terminating zero-length chunk and trailer CRLF.","On the receiving side, treat this UnexpectedEof as a truncated body — discard partial data; retry idempotent requests on a new connection.","If you generate chunked output, ensure the stream always emits the final 0-length chunk even on error paths."],"exampleFix":"// before: producer can drop without finishing the chunked stream\nlet body = Body::wrap_stream(producer_that_may_panic());\n\n// after: guarantee the terminal chunk by completing or converting to an error status\nlet body = Body::wrap_stream(async_stream::stream! {\n    let mut s = producer_that_may_panic();\n    while let Some(item) = s.next().await {\n        match item {\n            Ok(b) => yield Ok::<_, std::io::Error>(b),\n            Err(e) => { tracing::error!(\"producer failed: {e}\"); break; }\n        }\n    }\n});","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_chunk_eof(err: &hyper::Error) -> bool {\n    matches!(\n        err.source().and_then(|s| s.downcast_ref::<std::io::Error>()).map(|io| io.kind()),\n        Some(std::io::ErrorKind::UnexpectedEof)\n    )\n}","tryCatchPattern":"match hyper::body::to_bytes(resp.into_body()).await {\n    Ok(b) => Ok(b),\n    Err(e) if is_chunk_eof(&e) && idempotent => { /* truncated chunked body: retry */ }\n    Err(e) => Err(e),\n}","preventionTips":["Ensure chunked producers always emit the final zero-length chunk and trailer CRLF, even on error.","Treat UnexpectedEof mid-chunk as a truncated body; discard and retry idempotent requests.","Watch for proxies that time out and drop chunked streams before the terminating chunk."],"tags":["http1","chunked","body","eof","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}