hyperium/hyper · error · hyper::Error
received unexpected message from connection
Error message
received unexpected message from connection
What it means
Thrown via Error::new_unexpected_message() (src/error.rs:382, Kind::UnexpectedMessage), HTTP/1 only. It means the connection delivered a full new message (request or response) at a point in the state machine where none was expected — e.g. the server already moved on or the client got a second response head while not pipelining. Produced at proto/h1/conn.rs:465 and :488, and proto/h1/dispatch.rs:712.
Source
Thrown at src/error.rs:382
#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub(super) fn new_incomplete() -> Error {
Error::new(Kind::IncompleteMessage)
}
#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub(super) fn new_too_large() -> Error {
Error::new(Kind::Parse(Parse::TooLarge))
}
#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub(super) fn new_version_h2() -> Error {
Error::new(Kind::Parse(Parse::VersionH2))
}
#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub(super) fn new_unexpected_message() -> Error {
Error::new(Kind::UnexpectedMessage)
}
#[cfg(all(
any(feature = "client", feature = "server"),
any(feature = "http1", feature = "http2")
))]
pub(super) fn new_io(cause: std::io::Error) -> Error {
Error::new(Kind::Io).with(cause)
}
#[cfg(any(
all(feature = "http1", any(feature = "client", feature = "server")),
all(feature = "http2", feature = "client")
))]
pub(super) fn new_closed() -> Error {
Error::new(Kind::ChannelClosed)
}
View on GitHub (pinned to 084473f728)
Solutions
- Capture the peer's exact bytes with a packet capture (tcpdump/wireshark) to confirm it is sending data outside the expected HTTP/1 framing.
- If you control the peer, fix its request/response sequencing; otherwise treat the connection as corrupt and close it.
- Disable HTTP/1 pipelining assumptions and reuse the connection conservatively (open a fresh connection after such an error).
Example fix
// before: any connection error terminates the whole client
let resp = sender.send_request(req).await?;
// after: drop the corrupt connection and start a new one
match sender.send_request(req).await {
Err(e) => {
if !e.is_incomplete_message() {
// unexpected_message etc. => connection is unusable, reconnect
}
return Err(e);
}
Ok(r) => Ok(r),
} Defensive patterns
Strategy: try-catch
Type guard
// UnexpectedMessage isn't exposed as is_*(); match the description/source only
// for logging — do NOT depend on the string. Treat unknown connection errors
// as fatal for that connection.
fn is_connection_corrupt(_e: &hyper::Error) -> bool { /* not stable to detect */ false } Try / catch
if let Err(e) = sender.send_request(req).await {
// unexpected_message means the connection framing is broken
drop_connection_and_reconnect();
return Err(e);
} Prevention
- After any unexpected-message error, never reuse that connection — open a new one.
- Disable assumptions about HTTP/1 pipelining on either side.
- Capture the wire bytes when this recurs to find the peer that mis-sequences messages.
When it happens
Trigger: A client receives a response head while hyper is not waiting for one (conn.rs:465/488); the HTTP/1 dispatch loop gets a message when it expected a body continuation or idle (dispatch.rs:712). Often tied to an ill-behaved peer sending extra data, or a keep-alive reuse race after an error.
Common situations: A server that pipelines responses incorrectly; a buggy proxy injecting an extra response; a peer that sends a second request head inside what hyper thought was a body; protocol confusion after a 101 Upgrade or an informational response.
Related errors
- Invalid chunk size line: missing size digit
- Invalid chunk size line: Invalid Size
- Invalid chunk size linear white space
- Invalid chunk size LF
- Invalid chunk body CR
AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06).
Data as JSON: /data/errors/ad40d9e71689a1cc.json.
Report an issue: GitHub.