Hmbown/CodeWhale · error

MCP session expired (transport=sse endpoint={} status={}): {

Error message

MCP session expired (transport=sse endpoint={} status={}): {}

What it means

A POST to the SSE message endpoint failed and the body matched the stale-session classifier: is_mcp_stale_session_body() (crates/tui/src/mcp/wire.rs) looks for 'session' plus 'expired' or 'invalid', case-insensitive. The server no longer recognizes the session ID — it restarted, expired the session, or the POST landed on an instance without it. The connection must be re-established and re-initialized.

Source

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

            with_default_mcp_http_headers(self.client.post(&endpoint), true),
            &headers,
        )
        .body(msg)
        .send()
        .await
        .with_context(|| {
            format!(
                "MCP SSE POST send failed (transport=sse endpoint={})",
                mask_url_secrets(&endpoint)
            )
        })?;
        let status = response.status();
        if !status.is_success() {
            let body_excerpt = bounded_body_excerpt(response, ERROR_BODY_PREVIEW_BYTES).await;
            let stale_session = is_mcp_stale_session_body(&body_excerpt);
            let body_excerpt = self.auth.server_error_preview(&body_excerpt);
            if stale_session {
                anyhow::bail!(
                    "MCP session expired (transport=sse endpoint={} status={}): {}",
                    mask_url_secrets(&endpoint),
                    status,
                    body_excerpt
                );
            }
            anyhow::bail!(
                "MCP SSE POST rejected (transport=sse endpoint={} status={}): {}",
                mask_url_secrets(&endpoint),
                status,
                body_excerpt
            );
        }
        Ok(())
    }

    async fn recv(&mut self) -> Result<Vec<u8>> {
        loop {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Reconnect: tear down the transport and redo connect + initialize to obtain a fresh endpoint and session
  2. Rely on the client's stale-session reconnect handling (wire.rs is_mcp_stale_session_error) instead of retrying the same POST
  3. If frequent, increase the server's session TTL or add sticky sessions for the messages endpoint

Example fix

// before: retrying the same POST keeps failing
transport.send(request).await?;

// after: on stale session, reconnect and re-initialize
match transport.send(request).await {
    Err(e) if is_mcp_stale_session_error(&e) => {
        transport = reconnect(&config).await?; // fresh endpoint event + session
        initialize(&mut transport).await?;
        transport.send(request).await?
    }
    other => other?,
}
Defensive patterns

Strategy: retry

Type guard

```rust
// crates/tui/src/mcp/wire.rs already ships this classifier:
// is_mcp_stale_session_error(&err) matches "MCP session expired" and friends.
fn is_stale_sse_session(err: &anyhow::Error) -> bool {
    err.to_string().starts_with("MCP session expired (transport=sse")
}
```

Try / catch

```rust
match transport.send(payload).await {
    Err(e) if is_stale_sse_session(&e) => {
        transport = reconnect(&cfg).await?;   // fresh endpoint event + session
        initialize(&mut transport).await?;    // re-run initialize handshake
        transport.send(payload).await
    }
    other => other,
}
```

Prevention

When it happens

Trigger: The MCP SSE server restarts (deploy, crash) while the client holds an old session ID; server-side session TTL expiry on a long-lived connection; a load balancer without sticky sessions routing the POST to a different instance.

Common situations: Server upgraded mid-session; multi-instance deployments missing session affinity; idle connections outliving the server's session TTL.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/0bc57f2bc6db5b63. Report an issue: GitHub.