Hmbown/CodeWhale · error · anyhow::Error

MCP response body exceeds {max_bytes} bytes — aborting

Error message

MCP response body exceeds {max_bytes} bytes — aborting

What it means

The streamed body crossed max_bytes (MAX_MCP_RESPONSE_BYTES = 16 MiB) while read_body_capped() iterated the byte stream — the response was chunked or declared no Content-Length, so the upfront length guard could not catch it. Same OOM protection as the Content-Length guard, applied to the actual stream.

Source

Thrown at crates/tui/src/mcp/streamable_http.rs:181

}

/// Read a response body through the byte stream, failing as soon as it
/// exceeds `max_bytes`. This bounds chunked and missing-Content-Length
/// responses exactly like declared ones (the declared-length fast path in
/// `send` only covers servers honest enough to announce their size).
/// MCP bodies are JSON or SSE, so lossy UTF-8 matches `.text()` behavior.
pub(super) async fn read_body_capped(
    response: reqwest::Response,
    max_bytes: usize,
) -> Result<String> {
    use futures_util::StreamExt;

    let mut stream = response.bytes_stream();
    let mut buf: Vec<u8> = Vec::new();
    while let Some(chunk) = stream.next().await {
        let chunk = chunk.context("failed to read MCP response body")?;
        if buf.len().saturating_add(chunk.len()) > max_bytes {
            anyhow::bail!("MCP response body exceeds {max_bytes} bytes — aborting");
        }
        buf.extend_from_slice(&chunk);
    }
    Ok(String::from_utf8_lossy(&buf).into_owned())
}

fn is_streamable_http_incompatible_status(status: StatusCode) -> bool {
    matches!(
        status,
        StatusCode::NOT_FOUND
            | StatusCode::METHOD_NOT_ALLOWED
            | StatusCode::NOT_ACCEPTABLE
            | StatusCode::UNSUPPORTED_MEDIA_TYPE
            | StatusCode::NOT_IMPLEMENTED
    )
}

fn is_streamable_http_stale_session_status(status: StatusCode, body_excerpt: &str) -> bool {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Reduce the response size server-side: pagination, filters, returning references
  2. Check whether a gateway error page (huge HTML) replaced the real MCP response and fix the routing
  3. Ensure origin servers emit bounded bodies even when a proxy re-chunks them
Defensive patterns

Strategy: fallback

Try / catch

Identical to the declared-length variant: fall back to a narrower, paginated request; retrying the same call reproduces the same stream:
```rust
match fetch_resource(&id).await {
    Err(e) if e.to_string().contains("MCP response body exceeds") => {
        fetch_resource_range(&id, offset, limit).await
    }
    other => other?,
}
```

Prevention

When it happens

Trigger: A chunked or length-less MCP HTTP response whose accumulated body exceeds 16 MiB during the capped read.

Common situations: Servers streaming large tool outputs without a length; proxies re-chunking and stripping Content-Length; hostile servers lying about or omitting size.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/8b644e9e5d965ada. Report an issue: GitHub.