hyperium/hyper · error · hyper::Error

connection error

Error message

connection error

What it means

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.

Source

Thrown at src/error.rs:390

        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)
    }

    #[cfg(all(
        any(feature = "client", feature = "server"),
        any(feature = "http1", feature = "http2")
    ))]
    pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Body).with(cause)
    }

View on GitHub (pinned to 084473f728)

Solutions

  1. Inspect the source: downcast Error::source() to std::io::Error to get ErrorKind (UnexpectedEof, ConnectionReset, BrokenPipe, TimedOut, etc.) before deciding what to do.
  2. For transient kinds (ConnectionReset, BrokenPipe, UnexpectedEof) retry idempotent requests on a fresh connection.
  3. For connect-time failures, verify reachability (DNS, port, firewall, TLS) and add retries with backoff for the connection establishment step.

Example fix

// before: bubble up the opaque 'connection error'
let resp = client.get(uri).await?;

// after: classify the underlying io::Error to decide retry vs fail
match client.get(uri.clone()).await {
    Err(e) => {
        if let Some(io) = e.source().and_then(|s| s.downcast_ref::<std::io::Error>()) {
            match io.kind() {
                std::io::ErrorKind::ConnectionReset |
                std::io::ErrorKind::UnexpectedEof => { /* retry idempotent */ }
                _ => return Err(e),
            }
        } else { return Err(e); }
    }
    Ok(r) => return Ok(r),
}
Defensive patterns

Strategy: retry

Type guard

fn underlying_io(err: &hyper::Error) -> Option<&std::io::Error> {
    err.source()?.downcast_ref::<std::io::Error>()
}

fn is_transient_io(err: &hyper::Error) -> bool {
    matches!(
        underlying_io(err).map(|io| io.kind()),
        Some(std::io::ErrorKind::ConnectionReset)
            | Some(std::io::ErrorKind::BrokenPipe)
            | Some(std::io::ErrorKind::UnexpectedEof)
            | Some(std::io::ErrorKind::TimedOut)
            | Some(std::io::ErrorKind::WouldBlock)
    )
}

Try / catch

for attempt in 0..3u8 {
    match client.get(uri.clone()).await {
        Ok(r) => return Ok(r),
        Err(e) if attempt < 2 && is_transient_io(&e) && idempotent => {
            tokio::time::sleep(backoff(attempt)).await;
            continue;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06). Data as JSON: /data/errors/743de6b859044729.json. Report an issue: GitHub.