Hmbown/CodeWhale · error · StreamableSendError::Other

MCP response Content-Length

Error message

MCP response Content-Length {len} exceeds {} bytes — aborting

What it means

MCP responses are capped at MAX_MCP_RESPONSE_BYTES to prevent memory exhaustion. When the HTTP response declares a Content-Length above the cap, the client aborts before reading any body and raises this error. A separate capped reader (read_body_capped) additionally guards against length-less/chunked oversized streams.

Solutions

  1. Check what the server is returning — a multi-megabyte MCP response usually indicates a misbehaving tool or wrong endpoint
  2. Fix or bound the server-side tool that produces the oversized response
  3. If the deployment legitimately needs larger responses, raise MAX_MCP_RESPONSE_BYTES deliberately
Defensive patterns

Strategy: validation

Validate before calling

// before sending, sanity-check the endpoint returns bounded payloads:
// HEAD the URL and reject if Content-Length exceeds MAX_MCP_RESPONSE_BYTES

Try / catch

match client.send(request).await {
    Err(e) if e.to_string().contains("exceeds") && e.to_string().contains("aborting") => {
        // treat as server misbehavior; do not retry blindly, investigate the tool/endpoint
    }
    other => other?,
}

Prevention

When it happens

Trigger: send() receives a response whose content_length() exceeds MAX_MCP_RESPONSE_BYTES — i.e. the MCP server (or a proxy in front of it) returned a body larger than the configured maximum.

Common situations: A misconfigured endpoint returning a huge non-MCP payload (e.g. a data dump or log file); proxy injecting a large error page; genuinely huge tool result from a runaway server tool.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/d09585e2cd2be006. Report an issue: GitHub.

Appendix: source

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

                    mask_url_secrets(&self.url),
                    status,
                    body_excerpt,
                )));
            }

            let content_type = response
                .headers()
                .get(CONTENT_TYPE)
                .and_then(|value| value.to_str().ok())
                .map(str::to_string);
            // Reject an over-large declared body before reading anything (fast
            // path), then bound the read itself so chunked / length-less
            // responses cannot OOM us either — Content-Length alone does not
            // protect against a server that streams without declaring a length.
            if let Some(len) = response.content_length()
                && len > MAX_MCP_RESPONSE_BYTES as u64
            {
                return Err(StreamableSendError::Other(anyhow::anyhow!(
                    "MCP response Content-Length {len} exceeds {} bytes — aborting",
                    MAX_MCP_RESPONSE_BYTES
                )));
            }
            let body = read_body_capped(response, MAX_MCP_RESPONSE_BYTES)
                .await
                .map_err(StreamableSendError::Other)?;
            return self
                .store_response_body(content_type.as_deref(), &body)
                .map_err(StreamableSendError::Other);
        }
    }

    pub(super) async fn recv(&mut self) -> Result<Vec<u8>> {
        self.pending_messages
            .pop_front()
            .context("MCP Streamable HTTP response queue is empty")
    }

View on GitHub (pinned to 73e0f67d83)