seanmonstar/reqwest · error · reqwest::Error

request or response body error

Error message

request or response body error

What it means

The `Kind::Body` error from `error::body(...)` (error.rs:348-350). It fires when reading or writing the streaming body fails — most commonly a body read/write timeout (body.rs:309 and body.rs:352 wrap `TimedOut`), or an h3 pool stream body error (pool.rs:343/351).

Source

Thrown at src/error.rs:349

    Request,
    Redirect,
    #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
    Status(StatusCode, Option<hyper::ext::ReasonPhrase>),
    #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
    Status(StatusCode),
    Body,
    Decode,
    Upgrade,
}

// constructors

pub(crate) fn builder<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Builder, Some(e))
}

pub(crate) fn body<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Body, Some(e))
}

pub(crate) fn decode<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Decode, Some(e))
}

pub(crate) fn request<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Request, Some(e))
}

pub(crate) fn dns<E: Into<BoxError>>(e: E) -> BoxError {
    Box::new(DnsError { inner: e.into() })
}

pub(crate) fn redirect<E: Into<BoxError>>(e: E, url: Url) -> Error {
    Error::new(Kind::Redirect, Some(e)).with_url(url)
}

View on GitHub (pinned to 17e9bcb51c)

Solutions

  1. Raise or remove the timeout for large transfers: `.timeout(Duration::from_secs(300))` or per-request `.request_timeout`.
  2. Use `error.is_timeout()` to distinguish a body timeout from a genuine I/O failure and retry only timeouts.
  3. Stream the body in chunks instead of buffering, so progress resets the timeout window if using a per-byte deadline.
  4. Inspect `e.source()` for the underlying hyper/h3/io error to confirm it's not a real protocol failure.

Example fix

// before
let client = Client::builder().timeout(Duration::from_secs(5)).build()?;
let bytes = client.get(url).send().await?.bytes().await?; // body timeout on big payload

// after
let client = Client::builder().timeout(Duration::from_secs(120)).build()?;
let bytes = client.get(url).send().await?.bytes().await?;
Defensive patterns

Strategy: retry

Validate before calling

// No body-size pre-check, but size the timeout to the payload.
let timeout = estimate_timeout(payload_len, link_bps);
let client = Client::builder().timeout(timeout).build()?;

Type guard

fn is_body_or_body_timeout(e: &reqwest::Error) -> bool { e.is_body() || (e.is_timeout() && e.is_body()) }

Try / catch

match resp.bytes().await {
    Ok(b) => Ok(b),
    Err(e) if e.is_timeout() => retry().await,
    Err(e) if e.is_body() => Err(anyhow!("body error: {}", e.source().map(|s| s.to_string()).unwrap_or_default())),
    Err(e) => Err(e.into()),
}

Prevention

When it happens

Trigger: A request body upload or response body download exceeding the client/per-request `.timeout()`; the peer resets the stream mid-body; the response stream yields an h3/hyper body error during `.bytes()`/`.text()`/streaming.

Common situations: Large file upload over a slow link with a tight `.timeout(Duration::from_secs(5))`; streaming a huge JSON response that stalls; slow mobile network where the body never finishes in time; server closes the connection while you're still reading.

Related errors


AI-assisted analysis of seanmonstar/reqwest@17e9bcb51c (2026-08-06). Data as JSON: /data/errors/fbfad586e94b6d42.json. Report an issue: GitHub.