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.