Close request body async iterator when a write error occurs - #1119
Open
Dextheking1 wants to merge 5 commits into
Open
Dextheking1 wants to merge 5 commits into
Dextheking1 wants to merge 5 commits into
Conversation
If a `WriteError` is raised part-way through `_send_request_body`, the request body's async iterator was abandoned mid-iteration and later garbage collected without ever being exhausted, triggering `ResourceWarning: async generator was garbage collected before it had been exhausted` (encode/httpx#3597). Close the iterator in a `finally` block so it is cleaned up on both success and failure paths.
The _sync/http11.py and _sync/test_http11.py files are generated from their _async counterparts by scripts/unasync.py (enforced by 'scripts/check' in CI). Also annotate the new test's generator so mypy is clean.
Dextheking1
marked this pull request as ready for review
September 23, 2026 23:54
This branch has not been deployed
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.
Closes encode/httpx#3597.
What
AsyncHTTP11Connection._send_request_bodynow closes the request body's async iterator in afinallyblock, so it is cleaned up on both the success and failure paths.Why
When a
WriteErroris raised part-way through sending the request body,handle_async_requestcatches and suppresses it (to allow reading a pre-emptive error response from the server), but the request body's async iterator was left abandoned mid-iteration. It was then garbage collected without ever being exhausted, producing:Note: closing the iterator (rather than calling
request.stream.aclose()) is what fixes this, e.g. httpx'sByteStream.aclose()is a no-op, while the abandoned object is the generator created bystream.__aiter__(). Theaclosecall isgetattr-guarded so streams whose iterators lackaclosekeep working.Test evidence
New regression test
test_http11_write_error_closes_request_bodyintests/_async/test_http11.py: a network stream that raisesWriteErrormid-body, asserting the body iterator receivesGeneratorExitwhile theWriteErrorstays suppressed and the response remains readable.Before (on
master, trio backend):After: no warning;
tests/_async/test_http11.py, 28 passed (asyncio + trio backends).ruff checkandruff formatclean.