From be3193a29859a9d855e2535033a5703a647d467f Mon Sep 17 00:00:00 2001 From: goran-revops <46086727+goran-revops@users.noreply.github.com> Date: Thu, 24 Sep 2026 13:23:17 +0200 Subject: [PATCH 1/2] fix(proxy): share the parallel-request slot with the SSE keepalive task --- litellm/proxy/common_request_processing.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py index 2e43c6b0d22..83af9db99cd 100644 --- a/litellm/proxy/common_request_processing.py +++ b/litellm/proxy/common_request_processing.py @@ -1218,6 +1218,13 @@ async def open_sse_before_first_byte( if interval is None: return await produce_response + # The slot record must exist before this task is forked, or the release + # looks in the original task and never sees it. + from litellm.proxy.hooks.parallel_request_limiter_v3 import ( + get_or_create_request_stash, + ) + + get_or_create_request_stash() produce_task: Final = asyncio.ensure_future(produce_response) await asyncio.wait((produce_task,), timeout=interval) if produce_task.done(): From ca5e3106c4a8a871a4b794306c1215fa5cecfca4 Mon Sep 17 00:00:00 2001 From: goran-revops <46086727+goran-revops@users.noreply.github.com> Date: Thu, 24 Sep 2026 13:23:42 +0200 Subject: [PATCH 2/2] Test that the SSE keepalive task shares the parallel-request slot. --- .../proxy/test_sse_keepalive_request_stash.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/test_litellm/proxy/test_sse_keepalive_request_stash.py diff --git a/tests/test_litellm/proxy/test_sse_keepalive_request_stash.py b/tests/test_litellm/proxy/test_sse_keepalive_request_stash.py new file mode 100644 index 00000000000..d7c582d1ebe --- /dev/null +++ b/tests/test_litellm/proxy/test_sse_keepalive_request_stash.py @@ -0,0 +1,34 @@ +"""The SSE keepalive task must share the parallel-request slot with its caller.""" + +import asyncio + +from litellm.proxy.hooks.parallel_request_limiter_v3 import ( + _request_stash, + get_or_create_request_stash, + get_request_stash, +) + + +def test_sse_keepalive_fork_shares_the_parallel_request_slot(): + async def process(): + get_or_create_request_stash().owner_litellm_call_id = "call-1" + + async def without_seed(): + _request_stash.set(None) + task = asyncio.ensure_future(process()) + await asyncio.wait((task,)) + return get_request_stash() + + async def with_seed(): + _request_stash.set(None) + get_or_create_request_stash() + task = asyncio.ensure_future(process()) + await asyncio.wait((task,)) + return get_request_stash() + + leaked = asyncio.run(without_seed()) + shared = asyncio.run(with_seed()) + + assert leaked is None + assert shared is not None + assert shared.owner_litellm_call_id == "call-1"