{"id":"743de6b859044729","repo":"hyperium/hyper","slug":"connection-error","errorCode":null,"errorMessage":"connection error","messagePattern":"connection error","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":390,"sourceCode":"        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(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_io(cause: std::io::Error) -> Error {\n        Error::new(Kind::Io).with(cause)\n    }\n\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        all(feature = \"http2\", feature = \"client\")\n    ))]\n    pub(super) fn new_closed() -> Error {\n        Error::new(Kind::ChannelClosed)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {\n        Error::new(Kind::Body).with(cause)\n    }\n","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L372-L408","documentation":"Thrown via Error::new_io() (src/error.rs:390, Kind::Io). It wraps a std::io::Error that occurred while reading from or writing to the network stream — the generic 'something went wrong at the socket layer' variant. The real detail lives in the source chain (Error::source() downcast to std::io::Error): connection reset by peer, broken pipe, connection refused, TLS error, etc. Because it is the lowest-level IO bucket, the message alone is not enough — always inspect the source.","triggerScenarios":"Any read/write on the TcpStream (or TLS stream, or custom IO) returns an io::Error and hyper lifts it via new_io (error.rs:389). Also note the h2 path: new_h2 (error.rs:492) routes io-backed h2 errors here too (cause.is_io() branch). Fires on TCP RST, broken pipe after peer close, DNS/connect failures on the client, or a TLS handshake/alert.","commonSituations":"Peer crashed or network dropped mid-transfer (ECONNRESET/EOF); server process killed while client is reading; TLS misconfiguration surfacing as an IO error; a reverse proxy restarting; firewall/NAT dropping an idle connection with RST. Very common in any real networked deployment.","solutions":["Inspect the source: downcast Error::source() to std::io::Error to get ErrorKind (UnexpectedEof, ConnectionReset, BrokenPipe, TimedOut, etc.) before deciding what to do.","For transient kinds (ConnectionReset, BrokenPipe, UnexpectedEof) retry idempotent requests on a fresh connection.","For connect-time failures, verify reachability (DNS, port, firewall, TLS) and add retries with backoff for the connection establishment step."],"exampleFix":"// before: bubble up the opaque 'connection error'\nlet resp = client.get(uri).await?;\n\n// after: classify the underlying io::Error to decide retry vs fail\nmatch client.get(uri.clone()).await {\n    Err(e) => {\n        if let Some(io) = e.source().and_then(|s| s.downcast_ref::<std::io::Error>()) {\n            match io.kind() {\n                std::io::ErrorKind::ConnectionReset |\n                std::io::ErrorKind::UnexpectedEof => { /* retry idempotent */ }\n                _ => return Err(e),\n            }\n        } else { return Err(e); }\n    }\n    Ok(r) => return Ok(r),\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn underlying_io(err: &hyper::Error) -> Option<&std::io::Error> {\n    err.source()?.downcast_ref::<std::io::Error>()\n}\n\nfn is_transient_io(err: &hyper::Error) -> bool {\n    matches!(\n        underlying_io(err).map(|io| io.kind()),\n        Some(std::io::ErrorKind::ConnectionReset)\n            | Some(std::io::ErrorKind::BrokenPipe)\n            | Some(std::io::ErrorKind::UnexpectedEof)\n            | Some(std::io::ErrorKind::TimedOut)\n            | Some(std::io::ErrorKind::WouldBlock)\n    )\n}","tryCatchPattern":"for attempt in 0..3u8 {\n    match client.get(uri.clone()).await {\n        Ok(r) => return Ok(r),\n        Err(e) if attempt < 2 && is_transient_io(&e) && idempotent => {\n            tokio::time::sleep(backoff(attempt)).await;\n            continue;\n        }\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Always downcast Error::source() to std::io::Error before deciding — the top-level message is generic.","Retry only idempotent methods on transient io kinds; keep per-attempt and total timeouts.","Verify DNS/port/TLS/firewall separately when the failure is at connect time."],"tags":["network","io","tcp","tls","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}