Fix httpcore GeneratorExit in /v1/messages passthrough stream

Explicitly aclose aiter_lines() before the surrounding async with
blocks unwind, mirroring the prior fix in external_provider.py
(a41160d3) and cc757b78's RuntimeError suppression.
This commit is contained in:
Roland Tannous 2026-04-12 21:43:28 +04:00
commit 985e92a990

View file

@ -2672,21 +2672,36 @@ async def _anthropic_passthrough_stream(
json = body, json = body,
timeout = 600, timeout = 600,
) as resp: ) as resp:
async for raw_line in resp.aiter_lines(): # Explicitly manage the aiter_lines() iterator so it is
if await request.is_disconnected(): # closed in this task before the surrounding `async with`
cancel_event.set() # blocks unwind the response / client. Without this, the
return # inner httpcore byte-stream gets finalized by the GC in
if not raw_line or not raw_line.startswith("data: "): # a different asyncio task on Python 3.13 + httpcore 1.x,
continue # raising "Attempted to exit cancel scope in a different
data_str = raw_line[6:] # task" and "async generator ignored GeneratorExit".
if data_str.strip() == "[DONE]": lines_iter = resp.aiter_lines()
break try:
async for raw_line in lines_iter:
if await request.is_disconnected():
cancel_event.set()
return
if not raw_line or not raw_line.startswith("data: "):
continue
data_str = raw_line[6:]
if data_str.strip() == "[DONE]":
break
try:
chunk = json.loads(data_str)
except json.JSONDecodeError:
continue
for line in emitter.feed_chunk(chunk):
yield line
finally:
try: try:
chunk = json.loads(data_str) await lines_iter.aclose()
except json.JSONDecodeError: except RuntimeError:
continue # Python 3.13 + httpcore 1.0.x asyncgen cleanup
for line in emitter.feed_chunk(chunk): pass
yield line
except Exception as e: except Exception as e:
logger.error("anthropic_messages passthrough stream error: %s", e) logger.error("anthropic_messages passthrough stream error: %s", e)