Hmbown/CodeWhale · info

SSE transport cancelled before endpoint was discovered

Error message

SSE transport cancelled before endpoint was discovered

What it means

`wait_for_endpoint` blocks until the SSE server declares its message endpoint. If the cancellation token fires while waiting, the wait is aborted with this error (this branch takes priority over the timeout and channel receive in the select).

Solutions

  1. If unexpected, find what cancels the token during startup and defer it until after handshake
  2. Treat as benign teardown: catch and exit without retrying
  3. If the server is slow to send the endpoint event, fix the server or raise the endpoint timeout
Defensive patterns

Strategy: try-catch

Try / catch

match wait_for_endpoint(...).await {
    Err(e) if e.to_string().contains("cancelled before endpoint") => info!("aborted during handshake"),
    other => other?,
}

Prevention

When it happens

Trigger: Cancelling the token after the SSE stream connected but before the server sent its `endpoint` event.

Common situations: Shutdown or user abort mid-handshake; supervisor tearing down a hung server that never sent the endpoint event.

Related errors


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

Appendix: source

Thrown at crates/tui/src/mcp/sse.rs:215

                        return Ok(());
                    }
                }
            }
        }
        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");
            }
        }

View on GitHub (pinned to 73e0f67d83)