hyperium/hyper · error · hyper::Error

http2 error

Error message

http2 error

What it means

Thrown via Error::new_h2() (src/error.rs:492, Kind::Http2). It wraps an h2::Error from the HTTP/2 layer — a protocol, stream, or flow-control error reported by the h2 crate. (Note: if the h2 error is itself IO-backed, new_h2 routes it to Kind::Io instead — error.rs:493-495.) The real reason (h2::Reason such as INTERNAL_ERROR, ENHANCE_YOUR_CALM, NO_ERROR, PROTOCOL_ERROR) is in the source chain via h2_reason() (error.rs:353).

Source

Thrown at src/error.rs:496

        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)",
            Kind::Parse(Parse::Uri) => "invalid URI",
            #[cfg(all(feature = "http1", feature = "server"))]
            Kind::Parse(Parse::UriTooLong) => "URI too long",
            #[cfg(feature = "http1")]
            Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
            Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {
                "invalid content-length parsed"

View on GitHub (pinned to 084473f728)

Solutions

  1. Downcast the source to h2::Error and read .reason() (or use hyper's internal h2_reason) to get the precise h2::Reason before deciding.
  2. If the reason is ENHANCE_YOUR_CALM / max header list, reduce header sizes or raise the peer's advertised h2 settings; for flow-control, check send/recv window config.
  3. For NO_ERROR GOAWAY, reconnect and retry idempotent requests; for PROTOCOL_ERROR/INTERNAL_ERROR, treat the peer/connection as broken.

Example fix

// before: opaque 'http2 error' with no diagnosis
let resp = client.get(uri).await?;

// after: read the h2::Reason to drive recovery
match client.get(uri.clone()).await {
    Err(e) => {
        if let Some(h2err) = e.source().and_then(|s| s.downcast_ref::<h2::Error>()) {
            match h2err.reason() {
                Some(h2::Reason::NO_ERROR) | Some(h2::Reason::CANCEL) => { /* reconnect + retry */ }
                other => { /* log and fail */ }
            }
        }
        return Err(e);
    }
    Ok(r) => Ok(r),
}
Defensive patterns

Strategy: try-catch

Type guard

fn h2_reason(err: &hyper::Error) -> Option<h2::Reason> {
    err.source()?.downcast_ref::<h2::Error>()?.reason()
}

Try / catch

match client.get(uri.clone()).await {
    Err(e) => {
        if let Some(reason) = h2_reason(&e) {
            match reason {
                h2::Reason::NO_ERROR | h2::Reason::CANCEL | h2::Reason::REFUSED_STREAM => { /* retry */ }
                h2::Reason::ENHANCE_YOUR_CALM => { /* reduce header/load */ }
                _ => return Err(e),
            }
        } else { return Err(e); }
    }
    Ok(r) => return Ok(r),
}

Prevention

When it happens

Trigger: Any h2::Error surfaced from the HTTP/2 state machine: stream reset, flow-control violation, GOAWAY from the peer, SETTINGS timeout, header too large for h2's max frame size. new_h2 wraps it (error.rs:496) unless cause.is_io().

Common situations: Server/client set inconsistent SETTINGS (e.g. max frame size, max header list size); peer sends GOAWAY; flow-control deadlock; a header list bigger than the peer's MAX_HEADER_LIST_SIZE (often surfaces as ENHANCE_YOUR_CALM); h2 version or feature mismatch between peers.

Related errors


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