{"id":"ccd36f39a33143b7","repo":"hyperium/hyper","slug":"dispatch-task-is-gone","errorCode":null,"errorMessage":"dispatch task is gone","messagePattern":"dispatch task is gone","errorType":"exception","errorClass":"hyper::Error","httpStatus":null,"severity":"error","filePath":"src/error.rs","lineNumber":488,"sourceCode":"\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)\n        }\n    }\n\n    fn description(&self) -> &str {\n        match self.inner.kind {\n            Kind::Parse(Parse::Method) => \"invalid HTTP method parsed\",\n            #[cfg(feature = \"http1\")]\n            Kind::Parse(Parse::Version) => \"invalid HTTP version parsed\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::Parse(Parse::VersionH2) => \"invalid HTTP version parsed (found HTTP2 preface)\",","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/error.rs#L470-L506","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: conn future is not spawned, gets dropped -> dispatch task is gone\nlet (mut sender, conn) = hyper::client::conn::http1::handshake(stream).await?;\n// conn dropped here, so:\nlet _resp = sender.send_request(req).await?; // Err: dispatch task is gone\n\n// after: keep the dispatch task alive for the lifetime of the handle\nlet (mut sender, conn) = hyper::client::conn::http1::handshake(stream).await?;\ntokio::spawn(conn);\nlet resp = sender.send_request(req).await?;","handlingStrategy":"validation","validationCode":"// Always spawn the connection future returned by handshake; assert it lives.\nlet (sender, conn) = hyper::client::conn::http1::handshake(stream).await?;\nlet handle = tokio::spawn(conn); // keep the dispatch task alive\n// store `handle` alongside `sender` so you notice if the task ends","typeGuard":"fn is_dispatch_gone(err: &hyper::Error) -> bool {\n    err.is_user() // DispatchGone is under Kind::User; combine with message for finer detection\n}","tryCatchPattern":"match sender.send_request(req).await {\n    Err(e) if e.is_user() => {\n        // dispatch task is gone -> build a new connection and retry\n        let (sender, conn) = hyper::client::conn::http1::handshake(new_stream()).await?;\n        tokio::spawn(conn);\n        // retry with new sender\n    }\n    other => return other,\n}","preventionTips":["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."],"tags":["client","dispatch","lifecycle","tokio","rust"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}