Kuberwastaken/claurst · error · anyhow::Error
failed reading SSE stream
Error message
failed reading SSE stream: {} What it means
While consuming a server-sent-events stream from an MCP server, the reqwest bytes_stream yielded an Err. The library wraps the underlying transport error (hyper/reqwest/io) in this message, so the displayed cause is the raw stream read failure.
Solutions
- Retry the request; add reconnect/backoff logic for long SSE streams
- Check server and reverse-proxy idle timeouts and raise them
- Verify network/TLS stability between client and MCP server
- Inspect the wrapped cause (`{}` payload) for the concrete hyper/io error
Defensive patterns
Strategy: retry
Try / catch
match read_sse().await {
Err(e) if e.to_string().contains("failed reading SSE stream") => {
backoff_retry(|| read_sse(), 3).await?
}
r => r?,
} Prevention
- Raise LB/proxy idle timeouts for SSE connections
- Implement automatic reconnect with exponential backoff
- Monitor network/TLS health between client and MCP servers
When it happens
Trigger: Calling an MCP server over SSE and the TCP connection breaks mid-stream: server crash, network drop, proxy idle timeout, TLS termination, or reqwest body read error.
Common situations: Long-lived SSE connections killed by load balancer idle timeouts; server restarted during a request; flaky network or VPN disconnect; TLS certificate issues surfacing mid-stream.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- failed to resolve legacy SSE endpoint
- MCP server ' ': failed to read legacy SSE HTTP response body
- MCP server ' ': legacy SSE POST request failed
- models endpoint returned
- API key creation failed
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/bb66f5a52599885e.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/lib.rs:509
"data" => data_lines.push(value.to_string()),
_ => {}
}
}
pub(crate) async fn process_sse_response<F>(
response: reqwest::Response,
mut on_event: F,
) -> anyhow::Result<()>
where
F: FnMut(Option<&str>, &str) -> anyhow::Result<()>,
{
let mut stream = response.bytes_stream();
let mut buffer = String::new();
let mut event_name: Option<String> = None;
let mut data_lines: Vec<String> = Vec::new();
while let Some(chunk) = stream.next().await {
let chunk = chunk.map_err(|e| anyhow::anyhow!("failed reading SSE stream: {}", e))?;
buffer.push_str(&String::from_utf8_lossy(&chunk));
while let Some(pos) = buffer.find('\n') {
let mut line: String = buffer.drain(..=pos).collect();
if line.ends_with('\n') {
line.pop();
}
if line.ends_with('\r') {
line.pop();
}
if line.is_empty() {
dispatch_sse_event(&mut event_name, &mut data_lines, &mut on_event)?;
} else {
process_sse_line(&line, &mut event_name, &mut data_lines);
}
}
}
View on GitHub (pinned to b0637c97ec)