{"id":"6265313f5ad579c1","repo":"hyperium/hyper","slug":"connection-closed-before-message-completed","errorCode":null,"errorMessage":"connection closed before message completed","messagePattern":"connection closed before message completed","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":367,"sourceCode":"        None\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(super) fn h2_reason(&self) -> h2::Reason {\n        // Find an h2::Reason somewhere in the cause stack, if it exists,\n        // otherwise assume an INTERNAL_ERROR.\n        self.find_source::<h2::Error>()\n            .and_then(|h2_err| h2_err.reason())\n            .unwrap_or(h2::Reason::INTERNAL_ERROR)\n    }\n\n    pub(super) fn new_canceled() -> Error {\n        Error::new(Kind::Canceled)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_incomplete() -> Error {\n        Error::new(Kind::IncompleteMessage)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_too_large() -> Error {\n        Error::new(Kind::Parse(Parse::TooLarge))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_version_h2() -> Error {\n        Error::new(Kind::Parse(Parse::VersionH2))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_unexpected_message() -> Error {\n        Error::new(Kind::UnexpectedMessage)\n    }\n\n    #[cfg(all(","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L349-L385","documentation":"Thrown via Error::new_incomplete() (src/error.rs:367, Kind::IncompleteMessage), gated behind feature=\"http1\". It means the underlying IO reported EOF (a closed socket) while hyper's HTTP/1 state machine still expected more of the message — either the head or the body was only partially received. Detect it with Error::is_incomplete_message(). The hyper docs note common causes: a request sent on a connection whose next read is EOF (server closed an idle conn), a body cut short before Content-Length/chunk end, or a client that half-closes while you wait to respond.","triggerScenarios":"Reading the request/response head hits EOF before the terminating CRLF CRLF (proto/h1/io.rs:214, proto/h1/conn.rs:473 and :504); the dispatch sender is told the connection ended with an in-flight message (proto/h1/dispatch.rs:551). Happens when the peer closes the TCP stream partway through a request or response.","commonSituations":"An upstream reverse proxy/load balancer closes an idle keep-alive connection just as you send the next request; a client sends headers then closes the write half while the server is still computing a response (needs half_close enabled); a flaky mobile network drops the socket mid-body; a server with aggressive idle timeouts.","solutions":["Detect with Error::is_incomplete_message() and retry idempotent requests on a new connection rather than failing the user.","If you are a server whose client half-closes while awaiting a response, enable http1 half_close on the server Builder so the connection can still complete.","Tune keep-alive/idle timeouts on both peers so neither closes a connection the other is about to reuse, and drain bodies fully before returning."],"exampleFix":"// before: incomplete message aborts the whole operation\nlet resp = client.get(uri).await?;\n\n// after: retry on a fresh connection when the old one was cut mid-message\nasync fn fetch(client: &Client<...>, uri: Uri) -> Result<Response<Body>, hyper::Error> {\n    for attempt in 0..2u8 {\n        match client.get(uri.clone()).await {\n            Err(e) if e.is_incomplete_message() && attempt == 0 => continue,\n            res => return res,\n        }\n    }\n    unreachable!()\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_incomplete(err: &hyper::Error) -> bool {\n    err.is_incomplete_message()\n}","tryCatchPattern":"match client.get(uri.clone()).await {\n    Err(e) if e.is_incomplete_message() && idempotent => { /* retry on new connection */ }\n    other => other,\n}","preventionTips":["Fully drain request bodies before returning a response on the server side.","Enable http1 half_close on the server if clients half-close while awaiting a response.","Align keep-alive/idle timeouts across peers so neither reaps a connection the other is about to reuse."],"tags":["http1","network","connection","eof","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}