fix(streamable-http): surface transport faults to callers and message_handler
Closed
FU
2mo ago+130+130+012345678901234567890123456789-13-13-01234567890123456789
Fixes #1401
What changed
When a streamable-http response stream dies with a transport error (e.g.
httpx.ReadTimeout from sse_read_timeout), the original exception was
swallowed:
- The pending request was resolved with a generic
CONNECTION_CLOSEDerror
("SSE stream ended without a response" / "reconnection attempts were
exhausted"), hiding the root cause from user code. - The fault never reached
message_handler, even though theIncomingMessage
contract says transport-level exceptions are delivered there.
Now:
_handle_sse_responsecaptures the stream exception and forwards it into the
read stream as anExceptionitem, so the session'smessage_handler
observes the fault (custom handlers, like the one the reporter built as a
workaround, now receive it). The synthesized error keeps code
CONNECTION_CLOSEDand carries the exception in its message._handle_reconnectioncarries the latest failure through the retry loop and
includes it in the exhausted-budget error message.- New
_forward_stream_faulthelper, best-effort like
_resolve_abandoned_request.
How verified
- Updated
test_a_non_resumable_sse_drop_resolves_the_request_with_an_error
andtest_exhausted_reconnection_attempts_resolve_the_request_with_an_error
to assert the fault item and the exception in the error message. - Added
test_an_id_bearing_stream_that_dies_surfaces_the_fault_and_resolves_the_request
covering the reconnect-exhausted path end to end. pytest tests/client: 703 passed, 8 skipped, 1 xfailed; one unrelated
pre-existing failure intest_transport_stream_cleanup.py(also fails on
clean main on this machine).ruff check,ruff format, andpyrightclean.
Disclosure: this contribution was written with AI assistance and personally reviewed and tested by me.