fix: always create fresh httpx.Client to prevent use-after-close (#10324 regression)#11033
Closed
surmount1 wants to merge 1 commit into
Closed
fix: always create fresh httpx.Client to prevent use-after-close (#10324 regression)#11033surmount1 wants to merge 1 commit into
surmount1 wants to merge 1 commit into
Conversation
…sResearch#10324 regression) The guard introduced in NousResearch#10324 — if "http_client" not in client_kwargs: — caused a use-after-close bug in multi-turn sessions. Root cause: _create_request_openai_client() does a *shallow* copy of self._client_kwargs, so every per-request OpenAI client receives the same httpx.Client reference as the shared/init client. OpenAI.close() calls httpx.Client.close() internally, which marks the transport as closed. The first per-request client's cleanup therefore closes the shared transport, and every subsequent OpenAI client built from the same self._client_kwargs inherits a closed transport and immediately raises APIConnectionError("Connection error.") — typically observable on the 2nd API call within a session (e.g. after a tool result is returned). Fix: Remove the guard so _create_openai_client() always instantiates a fresh httpx.Client. Per-request clients now own their own transport; closing one does not affect any other client. Additionally, honour HTTPS_PROXY / HTTP_PROXY environment variables. httpx normally reads these automatically, but that behaviour is bypassed when a custom transport is passed. We forward the env vars explicitly so proxy settings work as expected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collaborator
|
The httpx keepalive code this patches was already reverted on main — |
This was referenced Apr 20, 2026
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.
Problem
The guard introduced in #10324 —
— caused a use-after-close bug that makes every multi-turn session fail with
APIConnectionError("Connection error.")starting from the second API call.Root Cause
_create_request_openai_client()does a shallow copy ofself._client_kwargs:Because the copy is shallow, every per-request
OpenAIclient receives the samehttpx.Clientreference as the shared/init client.OpenAI.close()callshttpx.Client.close()internally, which marks the underlying transport as closed. After the first per-request client is closed (e.g. after a tool-call result is processed), the sharedhttpx.Clientstored inself._client_kwargs["http_client"]is already closed. The nextOpenAIclient created from the same_client_kwargsinherits the closed transport and immediately raisesAPIConnectionError("Connection error.")without even attempting a network connection.Observed symptom: session consistently works for the first LLM call (initial response / tool decision), then fails on every subsequent call (processing tool results, follow-up turns).
Fix
Remove the
if "http_client" not in client_kwargs:guard so that_create_openai_client()always instantiates a freshhttpx.Client. Per-request clients now own their own transport; closing one does not affect any other client.As a bonus, also forward
HTTPS_PROXY/HTTP_PROXYenvironment variables explicitly. httpx normally reads proxy env vars automatically, but that behaviour is bypassed when a customtransport=is supplied — so users behind proxies would silently get no proxy support despite setting the standard env vars.Verification