hyperium/hyper · error · std::io::Error
end of file before message length reached
Error message
end of file before message length reached
What it means
Thrown in the HTTP/1 body decoder (src/proto/h1/decode.rs:161) as io::Error::new(UnexpectedEof, IncompleteBody) where IncompleteBody Display is 'end of file before message length reached' (decode.rs:681-687). It fires in the Length decoder when a read returns 0 bytes (EOF) before the full Content-Length body has been received (decode.rs:160-164). It is the specific, body-level form of 'incomplete message': the peer promised N bytes but closed early.
Source
Thrown at src/proto/h1/decode.rs:161
pub(crate) fn decode<R: MemRead>(
&mut self,
cx: &mut Context<'_>,
body: &mut R,
) -> Poll<Result<Frame<Bytes>, io::Error>> {
trace!("decode; state={:?}", self.kind);
match self.kind {
Length(ref mut remaining) => {
if *remaining == 0 {
Poll::Ready(Ok(Frame::data(Bytes::new())))
} else {
let to_read = usize::try_from(*remaining).unwrap_or(usize::MAX);
let buf = ready!(body.read_mem(cx, to_read))?;
let num = buf.as_ref().len() as u64;
if num > *remaining {
*remaining = 0;
} else if num == 0 {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
IncompleteBody,
)));
} else {
*remaining -= num;
}
Poll::Ready(Ok(Frame::data(buf)))
}
}
Chunked {
ref mut state,
ref mut chunk_len,
ref mut extensions_cnt,
ref mut trailers_buf,
ref mut trailers_cnt,
ref h1_max_headers,
ref h1_max_header_size,
} => {View on GitHub (pinned to 084473f728)
Solutions
- Confirm the peer actually sends exactly Content-Length bytes; fix length/transfer-encoding at the producer.
- On the receiving side, treat UnexpectedEof from the body as a corrupt/partial body — discard it and retry idempotent requests.
- If you proxy/transform bodies, recompute Content-Length (or use chunked) so you never advertise more than you send.
Example fix
// before: producer advertises a length it may not deliver
Response::builder()
.header("content-length", body_len.to_string())
.body(Body::from_stream(maybe_short_stream))?; // can EOF early
// after: use chunked when the length isn't guaranteed, or ensure the stream completes
Response::builder()
// omit content-length; hyper will use chunked transfer-encoding
.body(Body::from_stream(maybe_short_stream))? Defensive patterns
Strategy: retry
Validate before calling
// Validate advertised length against your policy before trusting it.
fn acceptable_content_length(headers: &HeaderMap) -> bool {
headers.get("content-length")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse::<usize>().ok())
.map(|n| n <= MAX_BODY_BYTES)
.unwrap_or(true)
} Type guard
fn is_truncated_body(err: &hyper::Error) -> bool {
// The IncompleteBody io::Error surfaces via Kind::Body; check the source.
matches!(
err.source().and_then(|s| s.downcast_ref::<std::io::Error>()).map(|io| io.kind()),
Some(std::io::ErrorKind::UnexpectedEof)
)
} Try / catch
match hyper::body::to_bytes(resp.into_body()).await {
Ok(bytes) => Ok(bytes),
Err(e) if is_truncated_body(&e) && idempotent => { /* discard, retry whole request */ }
Err(e) => Err(e),
} Prevention
- Producers must advertise exact Content-Length or use chunked; never overstate the length.
- Discard partial bodies on UnexpectedEof and retry idempotent requests.
- If you transform bodies in a proxy, recompute Content-Length or switch to chunked.
When it happens
Trigger: A request/response has a Content-Length header but the connection EOFs after delivering fewer bytes; the Length decoder's read_mem returns an empty slice (num == 0) while remaining > 0 (decode.rs:156-164). Also produced in the chunked Body state when a chunk read returns 0 early (decode.rs:489-494).
Common situations: Upstream mis-reports Content-Length (too large) and closes after the real bytes; a proxy truncates the body; a client uploads then disconnects before finishing; TLS layer closes early; buffering middleware that miscalculates length.
Related errors
- unexpected EOF during chunk size line
- connection closed before message completed
- error reading a body from connection
- operation was canceled
- message head is too large
AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06).
Data as JSON: /data/errors/111036985f028c04.json.
Report an issue: GitHub.