hyperium/hyper · error · hyper::Error

dispatch task is gone

Error message

dispatch task is gone

What it means

Thrown via Error::new_user_dispatch_gone() (src/error.rs:488, Kind::User(User::DispatchGone)), client side. It means the dispatch task — the future driving the connection returned by client::conn::handshake — is no longer running, so a send_request cannot be delivered. Produced in Callback::drop (client/dispatch.rs:242/249), with cause 'runtime dropped the dispatch task' or 'user code panicked' (dispatch.rs:257-263). Detect with Error::is_user() / the DispatchGone kind.

Source

Thrown at src/error.rs:488

    #[cfg(all(feature = "client", feature = "http2"))]
    pub(super) fn new_user_invalid_connect() -> Error {
        Error::new_user(User::InvalidConnectWithBody)
    }

    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
    pub(super) fn new_shutdown(cause: std::io::Error) -> Error {
        Error::new(Kind::Shutdown).with(cause)
    }

    #[cfg(feature = "ffi")]
    pub(super) fn new_user_aborted_by_callback() -> Error {
        Error::new_user(User::AbortedByCallback)
    }

    #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
    pub(super) fn new_user_dispatch_gone() -> Error {
        Error::new(Kind::User(User::DispatchGone))
    }

    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
    pub(super) fn new_h2(cause: ::h2::Error) -> Error {
        if cause.is_io() {
            Error::new_io(cause.into_io().expect("h2::Error::is_io"))
        } else {
            Error::new(Kind::Http2).with(cause)
        }
    }

    fn description(&self) -> &str {
        match self.inner.kind {
            Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
            #[cfg(feature = "http1")]
            Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",

View on GitHub (pinned to 084473f728)

Solutions

  1. Always spawn the connection future returned by handshake so it lives as long as the SendRequest handle: tokio::spawn(conn).
  2. On this error, discard the dead SendRequest and establish a new connection (handshake + spawn) before retrying.
  3. If the cause says 'user code panicked', find and fix the panic in your connection-driving code.

Example fix

// before: conn future is not spawned, gets dropped -> dispatch task is gone
let (mut sender, conn) = hyper::client::conn::http1::handshake(stream).await?;
// conn dropped here, so:
let _resp = sender.send_request(req).await?; // Err: dispatch task is gone

// after: keep the dispatch task alive for the lifetime of the handle
let (mut sender, conn) = hyper::client::conn::http1::handshake(stream).await?;
tokio::spawn(conn);
let resp = sender.send_request(req).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Always spawn the connection future returned by handshake; assert it lives.
let (sender, conn) = hyper::client::conn::http1::handshake(stream).await?;
let handle = tokio::spawn(conn); // keep the dispatch task alive
// store `handle` alongside `sender` so you notice if the task ends

Type guard

fn is_dispatch_gone(err: &hyper::Error) -> bool {
    err.is_user() // DispatchGone is under Kind::User; combine with message for finer detection
}

Try / catch

match sender.send_request(req).await {
    Err(e) if e.is_user() => {
        // dispatch task is gone -> build a new connection and retry
        let (sender, conn) = hyper::client::conn::http1::handshake(new_stream()).await?;
        tokio::spawn(conn);
        // retry with new sender
    }
    other => return other,
}

Prevention

When it happens

Trigger: You hold a SendRequest handle but the conn future it came from was dropped (not spawned / the task ended); the dispatch task panicked; the runtime was shut down. The next send_request hits the dropped Callback and returns dispatch_gone (dispatch.rs:240-252).

Common situations: Forgetting to tokio::spawn the conn future from client::conn::handshake (it gets dropped at end of scope); a panic inside the connection driver; runtime cancellation; reusing a client after the connection task exited.

Related errors


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