Skip to content

Getting raw exceptions instead of httpcore.ConnectError when using trio #224

Description

@florimondmanca

Description

Looks like we're missing an edge case in our trio backend — getting an OSError, socket.gaierror, etc, instead of a properly wrapped httpcore.ConnectError when requesting an unknown host.

Reproduces when using backend="anyio" too, as well as various versions of trio (0.17.*, 0.16.*), and on Python 3.8 and Python 3.9.

To reproduce

Assuming there's no server running on localhost:8000, run this script…

importhttpcoreimporttrio@trio.runasyncdefmain() ->None:
asyncwithhttpcore.AsyncConnectionPool() ashttp:
method=b"GET"url= (b"http", b"localhost", 8000, b"/")
awaithttp.arequest(method, url)

Expected behavior

Should be like when running on asyncio, i.e. raise a proper httpcore.ConnectError():

importasyncioimporthttpcoreasyncdefmain() ->None:
asyncwithhttpcore.AsyncConnectionPool() ashttp:
method=b"GET"url= (b"http", b"localhost", 8000, b"/")
awaithttp.arequest(method, url)
asyncio.run(main())
Traceback (most recent call last): File "/Users/florimond/Developer/python-projects/httpcore/debug/client.py", line 14, in <module> asyncio.run(main()) File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete return future.result() File "/Users/florimond/Developer/python-projects/httpcore/debug/client.py", line 11, in main await http.arequest(method, url) File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection_pool.py", line 218, in arequest response = await connection.arequest( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection.py", line 92, in arequest self.socket = await self._open_socket(timeout) File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection.py", line 118, in _open_socket return await self.backend.open_tcp_stream( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_backends/auto.py", line 44, in open_tcp_stream return await self.backend.open_tcp_stream( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_backends/asyncio.py", line 243, in open_tcp_stream return SocketStream( File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/contextlib.py", line 135, in __exit__ self.gen.throw(type, value, traceback) File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_exceptions.py", line 12, in map_exceptions raise to_exc(exc) from Nonehttpcore.ConnectError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 8000), [Errno 61] Connect call failed ('::1', 8000, 0, 0), [Errno 61] Connect call failed ('fe80::1', 8000, 0, 1)

Actual behavior

We get a raw OSError:

trio.MultiError: ConnectionRefusedError(61, 'Error in connect: Connection refused'), ConnectionRefusedError(61, 'Error in connect: Connection refused'), ConnectionRefusedError(61, 'Error in connect: Connection refused')Details of embedded exception 1: Traceback (most recent call last): File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_highlevel_open_tcp_stream.py", line 332, in attempt_connect await sock.connect(sockaddr) File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_socket.py", line 682, in connect raise OSError(err, "Error in connect: " + os.strerror(err)) ConnectionRefusedError: [Errno 61] Error in connect: Connection refusedDetails of embedded exception 2: Traceback (most recent call last): File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_highlevel_open_tcp_stream.py", line 332, in attempt_connect await sock.connect(sockaddr) File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_socket.py", line 682, in connect raise OSError(err, "Error in connect: " + os.strerror(err)) ConnectionRefusedError: [Errno 61] Error in connect: Connection refusedDetails of embedded exception 3: Traceback (most recent call last): File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_highlevel_open_tcp_stream.py", line 332, in attempt_connect await sock.connect(sockaddr) File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_socket.py", line 682, in connect raise OSError(err, "Error in connect: " + os.strerror(err)) ConnectionRefusedError: [Errno 61] Error in connect: Connection refusedThe above exception was the direct cause of the following exception:Traceback (most recent call last): File "/Users/florimond/Developer/python-projects/httpcore/debug/client.py", line 6, in <module> async def main() -> None: File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_core/_run.py", line 1928, in run raise runner.main_task_outcome.error File "/Users/florimond/Developer/python-projects/httpcore/debug/client.py", line 10, in main await http.arequest(method, url) File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection_pool.py", line 218, in arequest response = await connection.arequest( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection.py", line 92, in arequest self.socket = await self._open_socket(timeout) File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_async/connection.py", line 118, in _open_socket return await self.backend.open_tcp_stream( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_backends/auto.py", line 44, in open_tcp_stream return await self.backend.open_tcp_stream( File "/Users/florimond/Developer/python-projects/httpcore/httpcore/_backends/trio.py", line 154, in open_tcp_stream stream: trio.abc.Stream = await trio.open_tcp_stream( File "/Users/florimond/Developer/python-projects/httpcore/venv/lib/python3.9/site-packages/trio/_highlevel_open_tcp_stream.py", line 367, in open_tcp_stream raise OSError(msg) from trio.MultiError(oserrors)OSError: all attempts to connect to localhost:8000 failed

If we change the URL to point to an external host, like doesnotexistatall.org, we get a socket.gaierror:

[...]socket.gaierror: [Errno 8] nodename nor servname provided, or not known

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions