Hmbown/CodeWhale · error
SSE endpoint not received within {}ms
Error message
SSE endpoint not received within {}ms What it means
After connecting, the transport waits a bounded endpoint_timeout for the server's endpoint event, which declares the POST URL for messages. No endpoint event arrived before the deadline, so the transport gives up; the configured timeout in milliseconds is printed in the message.
Source
Thrown at crates/tui/src/mcp/sse.rs:218
}
}
Ok(())
}
async fn wait_for_endpoint(
&mut self,
cancel_token: &tokio_util::sync::CancellationToken,
endpoint_timeout: Duration,
) -> Result<()> {
let timeout = tokio::time::sleep(endpoint_timeout);
tokio::pin!(timeout);
let msg = tokio::select! {
_ = cancel_token.cancelled() => {
anyhow::bail!("SSE transport cancelled before endpoint was discovered");
}
_ = &mut timeout => {
anyhow::bail!(
"SSE endpoint not received within {}ms",
endpoint_timeout.as_millis()
);
}
msg = self.receiver.recv() => {
msg.context("SSE transport closed before endpoint was discovered")?
}
};
match msg {
SseInbound::Endpoint(endpoint) => self.store_endpoint(&endpoint),
SseInbound::Message(_) => {
anyhow::bail!("MCP SSE server sent a message before declaring its endpoint");
}
}
}
fn store_endpoint(&mut self, endpoint: &str) -> Result<()> {View on GitHub (pinned to 8880682c63)
Solutions
- Verify with curl -N <url> that an `event: endpoint` line arrives immediately after connect
- Match transport to endpoint: /sse with transport=sse, /mcp with transport=http
- Disable proxy buffering for event-stream responses (proxy_buffering off; X-Accel-Buffering: no)
- If the server is genuinely slow to handshake, fix its startup latency or raise the endpoint timeout
Defensive patterns
Strategy: validation
Validate before calling
```rust
// Before enabling a server: does the first streamed bytes contain `event: endpoint`?
async fn announces_endpoint(client: &reqwest::Client, url: &str) -> bool {
use futures_util::StreamExt;
let stream = match client.get(url).send().await { Ok(r) => r.bytes_stream(), Err(_) => return false };
tokio::pin!(stream);
let mut buf = Vec::new();
let deadline = tokio::time::Duration::from_secs(3);
while let Ok(Some(Ok(chunk))) = tokio::time::timeout(deadline, stream.next()).await {
buf.extend_from_slice(&chunk);
if buf.windows(15).any(|w| w == b"event: endpoint") { return true; }
}
false
}
``` Try / catch
```rust
match transport.wait_for_endpoint(&cancel, timeout).await {
Err(e) if e.to_string().contains("endpoint not received within") => {
fix_transport_or_url(); // wrong endpoint or buffering: do not blind-retry
}
other => other?,
}
``` Prevention
- curl -N every new SSE endpoint and confirm `event: endpoint` arrives immediately
- Disable proxy buffering for text/event-stream (proxy_buffering off; X-Accel-Buffering: no)
- Match transport=sse to /sse routes and transport=http to /mcp routes
When it happens
Trigger: A 200 response that never emits `event: endpoint` within the timeout: pointing transport=sse at a streamable-http /mcp route, a plain HTML page, or a proxy that buffers text/event-stream so events arrive late or never.
Common situations: Transport/URL mismatch; nginx/CDN buffering disabling streaming (missing proxy_buffering off); server that stalls before the handshake, e.g. waiting on auth.
Related errors
- Timed out waiting for MCP JSON-RPC response from server '{}'
- invalid JSON payload at key {MCP_SERVER_DEFINITIONS_KEY}; co
- invalid MCP server definition list in key {MCP_SERVER_DEFINI
- SSE stream idle timeout after {}s — no data received (bytes_
- SSE stream idle timeout after {}s — no data received (bytes_
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/d49078bd2768389d.
Report an issue: GitHub.