Hmbown/CodeWhale · error

MCP SSE POST rejected (transport=sse endpoint={} status={}):

Error message

MCP SSE POST rejected (transport=sse endpoint={} status={}): {}

What it means

The POST delivering a JSON-RPC message to the SSE endpoint returned a non-2xx status that is NOT classified as a stale session (no 'session expired/invalid' text in the body). The message carries the masked endpoint URL, the status, and a bounded, secret-scrubbed body excerpt for diagnosis.

Source

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

            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 {
            match self.receiver.recv().await.context("SSE transport closed")? {
                SseInbound::Endpoint(endpoint) => {
                    self.store_endpoint(&endpoint)?;
                }
                SseInbound::Message(msg) => return Ok(msg),
            }
        }

View on GitHub (pinned to 8880682c63)

Solutions

  1. Read the status and body excerpt embedded in the message — they state the actual failure
  2. On 401/403: refresh OAuth credentials and reconnect
  3. On 400: log the exact request JSON; the payload likely violates the server's schema for that method
  4. On 5xx: check server logs and retry with backoff once the server recovers
Defensive patterns

Strategy: try-catch

Type guard

```rust
fn sse_post_status(err: &anyhow::Error) -> Option<u16> {
    let msg = format!("{err:#}");
    msg.split("status=").nth(1)?.split(']').next()?  // e.g. "404): ..."
        .chars().take_while(char::is_ascii_digit)
        .collect::<String>().parse().ok()
}
```

Try / catch

```rust
match transport.send(payload).await {
    Err(e) if e.to_string().contains("MCP SSE POST rejected") => match sse_post_status(&e) {
        Some(s) if (500..600).contains(&s) => retry_with_backoff().await,
        Some(401) | Some(403) => reauthenticate_and_reconnect().await,
        _ => { log_body_excerpt(&e); return Err(e); }
    },
    other => other,
}
```

Prevention

When it happens

Trigger: POST to the endpoint event's URL answers 401/403 (auth header rejected), 400 (server rejects the JSON-RPC payload), 413, or a 5xx while processing a specific tool call.

Common situations: Token expired or revoked between connect and send; gateway rules (size, auth) on the POST route; server-side exception triggered by one particular tool call or resource read.

Related errors


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