{"record":{"id":"d49078bd2768389d","repo":"Hmbown/CodeWhale","slug":"sse-endpoint-not-received-within-ms","errorCode":null,"errorMessage":"SSE endpoint not received within {}ms","messagePattern":"SSE endpoint not received within (.+?)ms","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/sse.rs","lineNumber":218,"sourceCode":"            }\n        }\n        Ok(())\n    }\n\n    async fn wait_for_endpoint(\n        &mut self,\n        cancel_token: &tokio_util::sync::CancellationToken,\n        endpoint_timeout: Duration,\n    ) -> Result<()> {\n        let timeout = tokio::time::sleep(endpoint_timeout);\n        tokio::pin!(timeout);\n\n        let msg = tokio::select! {\n            _ = cancel_token.cancelled() => {\n                anyhow::bail!(\"SSE transport cancelled before endpoint was discovered\");\n            }\n            _ = &mut timeout => {\n                anyhow::bail!(\n                    \"SSE endpoint not received within {}ms\",\n                    endpoint_timeout.as_millis()\n                );\n            }\n            msg = self.receiver.recv() => {\n                msg.context(\"SSE transport closed before endpoint was discovered\")?\n            }\n        };\n\n        match msg {\n            SseInbound::Endpoint(endpoint) => self.store_endpoint(&endpoint),\n            SseInbound::Message(_) => {\n                anyhow::bail!(\"MCP SSE server sent a message before declaring its endpoint\");\n            }\n        }\n    }\n\n    fn store_endpoint(&mut self, endpoint: &str) -> Result<()> {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp/sse.rs#L200-L236","documentation":"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.","triggerScenarios":"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.","commonSituations":"Transport/URL mismatch; nginx/CDN buffering disabling streaming (missing proxy_buffering off); server that stalls before the handshake, e.g. waiting on auth.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"```rust\n// Before enabling a server: does the first streamed bytes contain `event: endpoint`?\nasync fn announces_endpoint(client: &reqwest::Client, url: &str) -> bool {\n    use futures_util::StreamExt;\n    let stream = match client.get(url).send().await { Ok(r) => r.bytes_stream(), Err(_) => return false };\n    tokio::pin!(stream);\n    let mut buf = Vec::new();\n    let deadline = tokio::time::Duration::from_secs(3);\n    while let Ok(Some(Ok(chunk))) = tokio::time::timeout(deadline, stream.next()).await {\n        buf.extend_from_slice(&chunk);\n        if buf.windows(15).any(|w| w == b\"event: endpoint\") { return true; }\n    }\n    false\n}\n```","typeGuard":null,"tryCatchPattern":"```rust\nmatch transport.wait_for_endpoint(&cancel, timeout).await {\n    Err(e) if e.to_string().contains(\"endpoint not received within\") => {\n        fix_transport_or_url(); // wrong endpoint or buffering: do not blind-retry\n    }\n    other => other?,\n}\n```","preventionTips":["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"],"tags":["mcp","sse","timeout","config"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}