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
- Always spawn the connection future returned by handshake so it lives as long as the SendRequest handle: tokio::spawn(conn).
- On this error, discard the dead SendRequest and establish a new connection (handshake + spawn) before retrying.
- 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
- Spawn the conn future from handshake immediately; never let it drop while you hold the sender.
- If the cause is 'user code panicked', locate and fix the panic in your connection driver.
- Detect DispatchGone and rebuild the connection rather than reusing the handle.
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
- channel closed
- operation was canceled
- connection closed before message completed
- message head is too large
- invalid HTTP version parsed (found HTTP2 preface)
AI-assisted analysis of hyperium/hyper@084473f728 (2026-08-06).
Data as JSON: /data/errors/ccd36f39a33143b7.json.
Report an issue: GitHub.