actix/actix-web · error · PayloadError

Response Payload IO timed out

Error message

Response Payload IO timed out

What it means

This is a runtime I/O error (`PayloadError::Io` with `ErrorKind::TimedOut`) raised when the client response body payload read exceeds the configured timeout. The `ResponseTimeout::poll_timeout` method at line 33-47 checks if the sleep timer has elapsed during body reading and returns this error to signal that the server took too long to send response data.

Solutions

  1. Increase or disable the response timeout: `client.get(url).timeout(Duration::from_secs(60)).send()`
  2. Set a global client timeout when building the client: `Client::builder().timeout(Duration::from_secs(120)).finish()`
  3. If the server is genuinely slow, consider streaming the body in chunks with explicit backpressure handling
  4. Verify the server is not hanging or deadlocked — the timeout may be correctly catching a broken upstream

Example fix

// before
let mut resp = client.get(url).send().await?;
let body = resp.body().await?; // times out on slow server

// after
let mut resp = client.get(url)
    .timeout(Duration::from_secs(120))
    .send().await?;
let body = resp.body().await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Set an appropriate timeout based on expected response time.
// For large/slow responses, increase or disable the timeout.
let resp = client.get(url)
    .timeout(Duration::from_secs(120))
    .send()
    .await?;

Try / catch

// Match on PayloadError to handle timeout gracefully.
use awc::error::SendRequestError;

match client.get(url).timeout(Duration::from_secs(30)).send().await {
    Ok(mut resp) => {
        match resp.body().await {
            Ok(body) => { /* process body */ }
            Err(awc::error::PayloadError::Io(e)) if e.kind() == std::io::ErrorKind::TimedOut => {
                // Handle timeout: retry, fallback, or return error
                eprintln!("Response body timed out");
            }
            Err(e) => { /* other payload error */ }
        }
    }
    Err(e) => { /* connection or request error */ }
}

Prevention

When it happens

Trigger: Calling `.send()` on an awc client request and then reading the response body (e.g., `.body()`, `.json()`) when the server is slow to send body chunks. The timeout is set via `ClientRequest::timeout()` or the client's default configuration.

Common situations: Downloading large files from a slow server, server-side streaming endpoints that trickle data, or network issues causing stalls. Also common when the default timeout is too short for the workload.

Understand the failure class

Related errors


AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09). Data as JSON: /api/errors/a28553555af33893. Report an issue: GitHub.

Appendix: source

Thrown at awc/src/responses/mod.rs:37

///
/// See [`ClientResponse::_timeout`] for reason.
pub(crate) enum ResponseTimeout {
    Disabled(Option<Pin<Box<Sleep>>>),
    Enabled(Pin<Box<Sleep>>),
}

impl Default for ResponseTimeout {
    fn default() -> Self {
        Self::Disabled(None)
    }
}

impl ResponseTimeout {
    fn poll_timeout(&mut self, cx: &mut Context<'_>) -> Result<(), PayloadError> {
        match *self {
            Self::Enabled(ref mut timeout) => {
                if timeout.as_mut().poll(cx).is_ready() {
                    Err(PayloadError::Io(io::Error::new(
                        io::ErrorKind::TimedOut,
                        "Response Payload IO timed out",
                    )))
                } else {
                    Ok(())
                }
            }
            Self::Disabled(_) => Ok(()),
        }
    }
}

View on GitHub (pinned to 4d435abc28)