AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

RunnableSequence.Astream Leaks TCP Socket FDs On Client Disconnect

RunnableSequence.astream() leaks one TCP socket FD per client disconnect when streaming via FastAPI/uvicorn. The leak is silent and FD count increases monotonically, eventually causing FD exhaustion and outage. Direct model.astream() or OpenAI SDK direct do not leak.

highConfidence 85%LangchainAffected V1.4.2

Origin Analysis

When a client disconnects mid-stream, Starlette cancels the response task via anyio cancel scope, throwing CancelledError through the nested async generator chain created by RunnableSequence. The httpx response __aexit__() is invoked during cleanup, but it internally awaits stream.aclose() to return the connection to the pool. This inner await is also cancelled by the same cancel scope, so the socket is never released. Direct model.astream() has a shorter cleanup path where __aexit__ completes before cancellation takes effect.
Run the provided FastAPI server with a RunnableSequence (prompt | model) and a streaming endpoint. Then run a client that repeatedly opens a stream and disconnects after receiving a few chunks. Observe the /health endpoint FD count increases by ~1 per interrupted stream; GC does not reclaim.

Fixing Code Block

Edge Case Audit

This is a monkey patch and may conflict with an official fix if applied simultaneously (double close is usually idempotent, but test thoroughly). It only patches RunnableSequence.astream, not other methods like stream in synchronous contexts. Ensure the event loop is running when the patch is applied. Rollback: reassign RunnableSequence.astream = _original_astream.

Ecosystem Topology