Summary
httpcore2/_backends/sync.py SyncBackend.connect_tcp passes the request timeout straight into socket.create_connection(address, timeout, ...). When a request's extensions["timeout"]["connect"] carries a Timeout object instead of a float (some SDK request builders do this — we hit it through the anthropic SDK path in hermes-agent), Python raises TypeError: 'Timeout' object cannot be interpreted as an integer before any network I/O, which the caller sees as a bogus APIConnectionError.
Reproducer (offline, no network needed)
import httpx2
from httpx2 import Timeout, Request, Client
r = Request("GET", "http://127.0.0.1:1/")
r.extensions["timeout"] = {"connect": Timeout(5.0)}
Client().send(r)
Result:
TypeError: 'Timeout' object cannot be interpreted as an integer
File ".../httpcore2/_backends/sync.py", line 204, in connect_tcp
sock = socket.create_connection(address, timeout, ...)
File ".../socket.py", line 845, in create_connection
sock.settimeout(timeout)
Environment
- httpcore2 / httpx2 2.7.0
- Python 3.11.13, macOS
Expected
socket.create_connection accepts only float | None. A Timeout object in the extensions should either be coerced (its numeric .connect attribute is the value) or surfaced as a clean error — not a stdlib TypeError from deep inside the connect path.
Suggested fix
In connect_tcp (and the same pattern in connect_unix_socket / start_tls):
if timeout is not None and not isinstance(timeout, (int, float)):
timeout = getattr(timeout, "connect", None)
We applied exactly this as a local patch and it resolves the failure.
Summary
httpcore2/_backends/sync.pySyncBackend.connect_tcppasses the request timeout straight intosocket.create_connection(address, timeout, ...). When a request'sextensions["timeout"]["connect"]carries aTimeoutobject instead of a float (some SDK request builders do this — we hit it through the anthropic SDK path in hermes-agent), Python raisesTypeError: 'Timeout' object cannot be interpreted as an integerbefore any network I/O, which the caller sees as a bogusAPIConnectionError.Reproducer (offline, no network needed)
Result:
Environment
Expected
socket.create_connectionaccepts onlyfloat | None. ATimeoutobject in the extensions should either be coerced (its numeric.connectattribute is the value) or surfaced as a clean error — not a stdlibTypeErrorfrom deep inside the connect path.Suggested fix
In
connect_tcp(and the same pattern inconnect_unix_socket/start_tls):We applied exactly this as a local patch and it resolves the failure.