{"id":"f0bbd56b52cc14b2","repo":"hyperium/hyper","slug":"error-shutting-down-connection","errorCode":null,"errorMessage":"error shutting down connection","messagePattern":"error shutting down connection","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"warning","filePath":"src/error.rs","lineNumber":478,"sourceCode":"        Error::new_user(User::Service).with(cause)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {\n        Error::new_user(User::Body).with(cause)\n    }\n\n    #[cfg(all(feature = \"client\", feature = \"http2\"))]\n    pub(super) fn new_user_invalid_connect() -> Error {\n        Error::new_user(User::InvalidConnectWithBody)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_shutdown(cause: std::io::Error) -> Error {\n        Error::new(Kind::Shutdown).with(cause)\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(super) fn new_user_aborted_by_callback() -> Error {\n        Error::new_user(User::AbortedByCallback)\n    }\n\n    #[cfg(all(feature = \"client\", any(feature = \"http1\", feature = \"http2\")))]\n    pub(super) fn new_user_dispatch_gone() -> Error {\n        Error::new(Kind::User(User::DispatchGone))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(super) fn new_h2(cause: ::h2::Error) -> Error {\n        if cause.is_io() {\n            Error::new_io(cause.into_io().expect(\"h2::Error::is_io\"))\n        } else {\n            Error::new(Kind::Http2).with(cause)","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L460-L496","documentation":"Thrown via Error::new_shutdown() (src/error.rs:478, Kind::Shutdown), HTTP/1 only. It wraps the std::io::Error returned by AsyncWrite::shutdown on the underlying stream — i.e. the graceful connection close sequence itself failed. Produced at proto/h1/conn.rs:851 (debug! \"error shutting down IO\"). Detect with Error::is_shutdown().","triggerScenarios":"Conn::poll_shutdown calls io.poll_shutdown (conn.rs:844-855) and the stream returns an io::Error (e.g. the peer already RST the connection, or TLS close_notify failed). Fires during the teardown path, typically after the real work is already done.","commonSituations":"Peer has already hard-closed the connection by the time hyper sends the shutdown; a TLS layer fails to exchange close_notify; a custom AsyncWrite (e.g. a proxy) errors on shutdown. Usually harmless because the response was already sent.","solutions":["Treat it as best-effort: the message exchange already completed in most cases, so log at debug/trace and continue rather than failing the request.","Detect with Error::is_shutdown() and downgrade severity in logs.","If using a custom IO/TLS layer, ensure its shutdown is robust to an already-closed peer."],"exampleFix":"// before: shutdown error fails the whole connection future\nlet (_tx, conn) = hyper::client::conn::http1::handshake(stream).await?;\nconn.await?;\n\n// after: a shutdown error after the work is done is not fatal\ntokio::spawn(async move {\n    if let Err(e) = conn.await {\n        if !e.is_shutdown() {\n            tracing::error!(\"connection error: {e}\");\n        } else {\n            tracing::debug!(\"connection shutdown reported error: {e}\");\n        }\n    }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_shutdown_err(err: &hyper::Error) -> bool {\n    err.is_shutdown()\n}","tryCatchPattern":"tokio::spawn(async move {\n    if let Err(e) = conn.await {\n        if e.is_shutdown() {\n            tracing::debug!(\"shutdown reported error (usually harmless): {e}\");\n        } else {\n            tracing::error!(\"conn error: {e}\");\n        }\n    }\n});","preventionTips":["After the response is delivered, treat shutdown errors as non-fatal (log debug).","Make custom/TLS AsyncWrite::shutdown tolerant of an already-closed peer.","Don't gate request success on a clean shutdown."],"tags":["http1","shutdown","connection","tls","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}