Skip to content

Replace a session's GET SSE stream instead of answering 409 - #37

Merged
dbernheisel merged 1 commit into
dbernheisel:mainfrom
satoren:fix/replace-stale-sse-stream
Oct 7, 2026
Merged

dbernheisel merged 1 commit into
dbernheisel:mainfrom
satoren:fix/replace-stale-sse-stream

Conversation

@satoren

@satoren satoren commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Problem

Cursor fails to connect with:

Client error: Streamable HTTP error: Failed to open SSE stream: Conflict
Client error: Maximum reconnection attempts (2) exceeded.

A second GET SSE stream for a session was refused with 409 Conflict. But a client that drops its GET stream is not noticed until the next write to it — the inactivity ping, up to session_timeout (30s by default) later. Until then the stale stream stays tracked, so a client reconnecting within that window is refused. (The official TypeScript/Python SDK servers also answer 409, but they notice the disconnect immediately, so they never hit a stale stream.)

Change

  • A GET for a session that already has a stream now casts :replaced to the existing stream(s), on any node, and takes over as the session's stream.
  • The replaced stream sends a closed / replaced event and shuts down.
  • The 409 test is replaced with one asserting the takeover.

Notes

  • The spec allows multiple streams; the official SDK clients hold one GET stream, so a takeover only happens on reconnect.
  • Resource subscriptions held by the replaced stream are dropped, as they were before when the stale stream eventually timed out.

🤖 Generated with Claude Code

A client that drops its GET stream is not noticed until the next write,
up to session_timeout later, so a reconnect within that window was
refused with 409 Conflict while the stale stream lingered. Cursor gives
up after two such attempts. A new GET for the session now tells the
existing stream (on any node) to close and takes over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dbernheisel
dbernheisel merged commit 86b3150 into dbernheisel:main Oct 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants