🐛 Fix response_class=EventSourceResponse sending an empty body for non-generator endpoints - #16192
Open
SEPURI-SAI-KRISHNA wants to merge 1 commit into
Open
Conversation
response_class=EventSourceResponse sending an empty body for non-generator endpoints
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See #16107
A path operation declared with
response_class=EventSourceResponsethat is not a generator is dispatched into the SSE branch anyway, becauseget_request_handler()recomputesis_sse_streamfrom the response class alone, with no generator check.The branch is entered before the endpoint runs, so
dependant.call(...)yields a coroutine (or a plain value) where an iterator is expected, and the200andtext/event-streamheaders are already flushed by the time it fails. Two symptoms, both silent:async defreturns200with an empty body, plusRuntimeWarning: coroutine ... was never awaited. Under uvicorn it is worse than empty:iterate_in_threadpool()raisesTypeError: 'coroutine' object is not iterablemid-response, the connection truncates, and the client getsRemoteProtocolError: peer closed connection without sending complete message body.sync defreturns200streaming the iteration of the return value with no error at all, so an endpoint returning{"msg": "hello"}putsdata: "msg"on the wire.The same value is already computed correctly on the route, with the generator check fused in, right beside its JSONL sibling:
but only
is_json_streamis passed down, so the two disagree for every non-generator endpoint.This PR removes the local recomputation and threads
route.is_sse_streamthrough as a parameter, exactly asroute.is_json_streamalready was, so both flags are derived in one place. The local recomputation appears to have guarded againstresponse_classbeing aDefaultPlaceholder, butadd_api_route()already resolves that viaget_value_or_default()before the route is built, so the route attribute is correct in precisely that case — verified for app-level and router-leveldefault_response_class=EventSourceResponse, whereroute.is_sse_streamstaysTrueand OpenAPI still documentstext/event-stream.Present since SSE was added in
0.135.0; verified against stock0.135.0and0.141.0.Adds
tests/test_sse_non_generator.pycovering:EventSourceResponsedirectlyThree of the four fail on
master— two withTypeError: 'coroutine' object is not iterable, and the sync one with a plain assertion showingdata: "msg"on the wire.