High severity intermediate · Fix: 5-10 min

ConnectionResetError

builtins.ConnectionResetError

What this error means
The SSE connection using FastAPI's EventSourceResponse unexpectedly closes due to client disconnects or server-side write failures.

Stack trace

traceback
Traceback (most recent call last):
  File "/app/main.py", line 45, in event_generator
    yield f"data: {message}\n\n"
  File "/usr/local/lib/python3.9/site-packages/starlette/responses.py", line 123, in __call__
    await send({"type": "http.response.body", "body": chunk.encode(), "more_body": True})
  File "/usr/local/lib/python3.9/asyncio/streams.py", line 541, in write
    self._transport.write(data)
  File "/usr/local/lib/python3.9/asyncio/selector_events.py", line 103, in write
    raise ConnectionResetError('Cannot write to closing transport')
builtins.ConnectionResetError: Cannot write to closing transport
QUICK FIX
Wrap the SSE event generator's yield/send calls in try/except ConnectionResetError to handle client disconnects gracefully.

Why it happens

SSE connections rely on a persistent HTTP connection to stream events. If the client disconnects abruptly or the server tries to write to a closed connection, a ConnectionResetError occurs. Network interruptions, client timeouts, or improper server-side handling of disconnects cause this error.

Detection

Monitor server logs for ConnectionResetError during SSE streaming and implement exception handling around the event generator to detect client disconnects gracefully.

Causes & fixes

1

Client closes the SSE connection unexpectedly (e.g., browser tab closed or network lost)

✓ Fix

Catch ConnectionResetError in the event generator and stop yielding events to cleanly close the connection.

2

Server attempts to write to the SSE stream after the client has disconnected

✓ Fix

Add try/except around yield/send calls in the SSE generator to handle ConnectionResetError and terminate the generator.

3

No heartbeat or keep-alive messages causing proxies or clients to drop the connection

✓ Fix

Implement periodic heartbeat events (e.g., sending a comment line ': keep-alive\n\n') to keep the connection alive.

Code: broken vs fixed

Broken - triggers the error
python
from fastapi import FastAPI
from starlette.responses import EventSourceResponse

app = FastAPI()

async def event_generator():
    while True:
        message = "Hello"
        yield f"data: {message}\n\n"  # This line raises ConnectionResetError on client disconnect

@app.get("/sse")
async def sse_endpoint():
    return EventSourceResponse(event_generator())
Fixed - works correctly
python
import os
from fastapi import FastAPI
from starlette.responses import EventSourceResponse

app = FastAPI()

async def event_generator():
    try:
        while True:
            message = "Hello"
            yield f"data: {message}\n\n"  # Wrapped in try/except to handle disconnects
    except ConnectionResetError:
        print("Client disconnected, stopping event generator")
        return

@app.get("/sse")
async def sse_endpoint():
    return EventSourceResponse(event_generator())  # Fixed: added disconnect handling
Added try/except ConnectionResetError around the yield to catch client disconnects and stop the generator cleanly, preventing server errors.
⚠

Workaround

Wrap the SSE generator yield calls in try/except ConnectionResetError and silently stop yielding events when the client disconnects to avoid crashes.

✓

Prevention

Implement heartbeat messages in the SSE stream and robustly handle client disconnect exceptions to maintain stable SSE connections in production.

Python 3.9+ · fastapi >=0.65.0 · tested on 0.95.0
Verified 2026-04
Verify ↗

Community Notes

No notes yetBe the first to share a version-specific fix or tip.