hyperium/hyper · warning · hyper::Error

operation was canceled

Error message

operation was canceled

What it means

Thrown via Error::new_canceled() (src/error.rs:362, Kind::Canceled). It means a pending request/response operation was dropped or the connection went away before the operation could be dispatched or completed. hyper does not consider this a hard protocol failure — it is reported distinctly and you can detect it with Error::is_canceled(). In practice it is often benign (the caller no longer cares about the result), but it can also surface when the underlying connection died while a request was queued.

Source

Thrown at src/error.rs:362

            }
            cause = err.source();
        }

        // else
        None
    }

    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
    pub(super) fn h2_reason(&self) -> h2::Reason {
        // Find an h2::Reason somewhere in the cause stack, if it exists,
        // otherwise assume an INTERNAL_ERROR.
        self.find_source::<h2::Error>()
            .and_then(|h2_err| h2_err.reason())
            .unwrap_or(h2::Reason::INTERNAL_ERROR)
    }

    pub(super) fn new_canceled() -> Error {
        Error::new(Kind::Canceled)
    }

    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
    pub(super) fn new_incomplete() -> Error {
        Error::new(Kind::IncompleteMessage)
    }

    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
    pub(super) fn new_too_large() -> Error {
        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"))]

View on GitHub (pinned to 084473f728)

Solutions

  1. Check Error::is_canceled() and treat it as non-fatal — for idempotent requests, retry on a fresh connection rather than propagating.
  2. If you intentionally drop response futures (e.g. fire-and-forget), expect and ignore this variant explicitly instead of logging it as an error.
  3. If cancellations are unexpected, audit the call site for a wrapping timeout, a Select that drops the losing branch, or a connection pool evicting an idle connection mid-request.

Example fix

// before: any error is fatal
let resp = client.get(uri).await?;

// after: distinguish cancellation from real errors
match client.get(uri).await {
    Ok(resp) => { /* ... */ }
    Err(e) if e.is_canceled() => {
        // request was dropped / connection closed mid-flight; retry idempotent calls
    }
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: type-guard

Type guard

// hyper exposes the predicate directly; wrap for readability
fn is_canceled(err: &hyper::Error) -> bool {
    err.is_canceled()
}

Try / catch

match client.get(uri).await {
    Ok(resp) => { /* handle */ }
    Err(e) if e.is_canceled() => { /* dropped/disconnected mid-flight: retry idempotent */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling send_request on a client::conn SendRequest and dropping the returned Response future before it resolves; the HTTP/1 dispatch loop seeing the connection close while a request is still queued (proto/h1/dispatch.rs:729, .with("connection closed")); a client send_request that finds the connection 'was not ready' and exhausts its retry (client/conn/http1.rs:229, client/conn/http2.rs:167).

Common situations: A request future is abandoned because a wrapping timeout (tokio::time::timeout) elapsed and dropped it; a single shared connection is reused across many concurrent tasks and one task is cancelled; an upstream is slow and the caller gives up. Usually appears alongside a tokio cancel/cancellation.

Related errors


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