Skip to content

Windows - Python 3.8+ raises "RuntimeError: Event Loop is closed" on exit. #914

Open

Description

@rmawatson

Checklist

  • [ x] The bug is reproducible against the latest release and/or master.
  • [ x] There are no similar issues or pull requests to fix it yet.

Describe the bug

I get the following traceback when running the attached code

404
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x0000017C63D5E310>
Traceback (most recent call last):
  File "C:\Python\Python38\lib\asyncio\proactor_events.py", line 116, in __del__
    self.close()
  File "C:\Python\Python38\lib\asyncio\proactor_events.py", line 108, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\Python\Python38\lib\asyncio\base_events.py", line 715, in call_soon
    self._check_closed()
  File "C:\Python\Python38\lib\asyncio\base_events.py", line 508, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

To reproduce

async def testing():
    client = httpx.AsyncClient()
    response = await client.get("https://www.google.com/")
    await client.aclose()
    print(response.status_code)

async def main():
   await testing()

asyncio.run(main())

Inserting time.sleep(0.1) at the end of main() fixes it. Possibly due to the same reasons in the issues linked below.

Environment

  • Windows 10 64bit
  • Python version: 3.8.1
  • HTTPX version 0.12.1

Possibly the same as this and this

Activity

  1. florimondmanca commented on Apr 30, 2020

    @florimondmanca
    Contributor

    I assume this is yet another strange issue with asyncio’s stream.close() - it schedules the closing of the socket but it’s not guaranteed to be done once client.aclose finishes, which means the socket is actually deleted upon garbage collection, and by then I suppose the event loop is already closed... The sleep() call fixed this because it allows asyncio to execute the close callback before proceeding to shutdown the async environment.

    See also #825 for more discussion on a possibly related issue.

    Have you tried running this on Python 3.8.2?

  2. lovelydinosaur commented on Apr 30, 2020

    @lovelydinosaur
    Member

    Also: May well be specific to Window's Proactor event loop.

  3. florimondmanca commented on Apr 30, 2020

    @florimondmanca
    Contributor

    Yes, definitely looks like a Windows specific issue to me - the linked issues are for Windows too.

  4. rmawatson commented on Apr 30, 2020

    @rmawatson
    Author

    @florimondmanca , yes upgraded to 3.8.2 to check, the result is the same.

  5. Baysul commented on May 1, 2020

    @Baysul

    Can confirm this is an issue with the latest PyPi version of aiohttp and Python 3.8.2 on Windows.

  6. florimondmanca commented on May 1, 2020

    @florimondmanca
    Contributor

    Okay, thank you.

    I personally don’t have a Windows machine so help with investigation and possible fixes would help.

    Would we need to consider black magic such as aio-libs/aiohttp#1925 (comment)? How about aio-libs/aiohttp#3733?

    FYI this is likely to be something to address on the HTTPCore side, as connection management and networking is done there. Might then be helpful to first come up with a minimal repro example using HTTPCore only?

  7. lovelydinosaur commented on May 1, 2020

    @lovelydinosaur
    Member

    It'd also be helpful to try switching to using SelectorEventLoop and let us know what the behaviour is like then... https://docs.python.org/3/library/asyncio-eventloop.html#event-loop-implementations (Or to try with Python 3.7 or earlier)

    Python only switched the default event loop to proactor from 3.8 onwards. https://docs.python.org/3/library/asyncio-policy.html#asyncio.DefaultEventLoopPolicy

  8. euri10 commented on May 1, 2020

    @euri10
    Contributor
  9. Baysul commented on May 1, 2020

    @Baysul

    The workaround is to use the selector event loop like this:

    import sys
    import asyncio
    
    if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith('win'):
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    The following from the documentation will not resolve this issue (for some reason):

    import asyncio
    import selectors
    
    selector = selectors.SelectSelector()
    loop = asyncio.SelectorEventLoop(selector)
    asyncio.set_event_loop(loop)
  10. rmawatson commented on May 2, 2020

    @rmawatson
    Author

    Thanks @Baysul.

    This bug report looks like it is tracking the same issue.

  11. lovelydinosaur commented on May 6, 2020

    @lovelydinosaur
    Member

    Same as with #825 - Haven't looked into how awkward it is to do, but really I think we'd want to monkeypatch asyncio's socket unwrapping behaviour, so that we can reliably call .wait_closed(...) without it potentially hanging.

  12. added
    externalRoot cause pending resolution in an external dependency
    on May 13, 2020
  13. lovelydinosaur commented on Aug 20, 2020

    @lovelydinosaur
    Member

    Can anyone on Windows, running Python 3.8+ confirm what currently happens when running this?...

    import httpx
    import asyncio
    
    async def main():
        async with httpx.AsyncClient() as client:
            r = await client.get("https://login.microsoftonline.com/")
            print(r)
    
    asyncio.run(main(), debug=True)

    Trying to verify if we're still exposed to this issue. (I guess we are but 🤷‍♂️)

  14. 21 remaining items

  15. pprovart commented on Feb 10, 2022

    @pprovart

    Windows 10
    Python 3.10.2
    NOTE: Problem occured before and after i installed httpx and httpcore
    httpcore 0.14.7
    httpx 0.22.0

    Code gets the required data from BSCSCAN and then i get the Runtime Error.
    The time.sleep(1) command didnt work.

    PYTHON
    import asyncio
    from bscscan import BscScan

    YOUR_API_KEY = "REDACTED"
    CON_ADDR = "0xa38898a4ae982cb0131104a6746f77fa0da57aaa"
    WAL_ADDR = "0x411709fd0cdd5f06ff6ef45b48aa0cb9842f01fc"

    async def main():
    async with BscScan(YOUR_API_KEY) as bsc:
    print(await bsc.get_bnb_balance(address="0xa38898a4ae982cb0131104a6746f77fa0da57aaa")

    if name == "main":
    asyncio.run(main())

    OUTPUT
    image

  16. aabmets commented on Feb 24, 2022

    @aabmets

    I'm having the same issue on Windows 10. It does not matter what library I'm using.
    If the loop is an ProactorEventLoop, then it is guaranteed that it will cause an exception if
    there have been any network requests made which use SSL or sessions.

  17. lovelydinosaur commented on Feb 25, 2022

    @lovelydinosaur
    Member

    Okay - could you show me that absolute simplest possible example that reproduces this.

    @pprovart's example here is pretty good - does it still replicate if you simplify it even further?...

    import asyncio
    import httpx
    
    async def main():
        async with httpx.Client() as client:
            r = await client.get("https://www.example.com")
            print(r)
    
    if name == "main":
        asyncio.run(main())

    Also, does it replicate with both http and https URLs?

  18. lovelydinosaur commented on Feb 25, 2022

    @lovelydinosaur
    Member

    @Mennaruuk - Ah yup. Just looked though this thread and reminded myself of the comment here.

    This is a bug in Python's stdlib with Windows. See: https://bugs.python.org/issue39232

    One option here might be to check if the ProactorEventLoop is the default, and warn if it is.

  19. graingert commented on Jun 18, 2022

    @graingert
    Contributor

    when using async with httpx.AsyncClient() as client the transport should be closed correctly by anyio and not trigger the __del__ so this looks like an anyio bug

  20. lovelydinosaur commented on Dec 11, 2022

    @lovelydinosaur
    Member

    This bug in the Python stdlib appears to have been fixed now in 3.11 (and possibly backported to 3.10?)

    python/cpython#83413

    Are any windows users here able to attempt replicating the original issue on the latest patch versions of Python 3.9, 3.10 and 3.12?

  21. mbwmbw1337 commented on Dec 11, 2022

    @mbwmbw1337

    This bug in the Python stdlib appears to have been fixed now in 3.11 (and possibly backported to 3.10?)

    python/cpython#83413

    Are any windows users here able to attempt replicating the original issue on the latest patch versions of Python 3.9, 3.10 and 3.12?

    I can test later today.

  22. FANGOD commented on Jan 18, 2023

    @FANGOD

    This problem also occurs on linux.

    Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x7f85c758ce50>
    Traceback (most recent call last):
      File "/usr/lib/python3.8/asyncio/base_subprocess.py", line 126, in __del__
        self.close()
      File "/usr/lib/python3.8/asyncio/base_subprocess.py", line 104, in close
        proto.pipe.close()
      File "/usr/lib/python3.8/asyncio/unix_events.py", line 536, in close
        self._close(None)
      File "/usr/lib/python3.8/asyncio/unix_events.py", line 560, in _close
        self._loop.call_soon(self._call_connection_lost, exc)
      File "/usr/lib/python3.8/asyncio/base_events.py", line 711, in call_soon
        self._check_closed()
      File "/usr/lib/python3.8/asyncio/base_events.py", line 504, in _check_closed
        raise RuntimeError('Event loop is closed')
    RuntimeError: Event loop is closed
    
  23. kpostekk commented on Jan 18, 2023

    @kpostekk

    This problem also occurs on linux.

    Have you considered switching to recent version of python?

  24. piscesvivian commented on Aug 1, 2025

    @piscesvivian

    V-0.28.1 Windows The error is still there

    ERROR Task exception was never retrieved
    future: <Task finished name='Task-288' coro=<AsyncClient.aclose() done, defined at \.venv\Lib\site-packages\httpx\_client.py:1978> exception=RuntimeError('Event loop is closed')>
    Traceback (most recent call last):
      File "\.venv\Lib\site-packages\httpx\_client.py", line 1985, in aclose
        await self._transport.aclose()
      File "\.venv\Lib\site-packages\httpx\_transports\default.py", line 406, in aclose
        await self._pool.aclose()
      File "\.venv\Lib\site-packages\httpcore\_async\connection_pool.py", line 353, in aclose
        await self._close_connections(closing_connections)
      File "\.venv\Lib\site-packages\httpcore\_async\connection_pool.py", line 345, in _close_connections
        await connection.aclose()
      File "\.venv\Lib\site-packages\httpcore\_async\connection.py", line 173, in aclose
        await self._connection.aclose()
      File "\.venv\Lib\site-packages\httpcore\_async\http11.py", line 258, in aclose
        await self._network_stream.aclose()
      File "\.venv\Lib\site-packages\httpcore\_backends\anyio.py", line 53, in aclose
        await self._stream.aclose()
      File "\.venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 1314, in aclose
        self._transport.close()
      File "C:\Users\<user>\AppData\Roaming\uv\python\cpython-3.12.10-windows-x86_64-none\Lib\asyncio\proactor_events.py", line 109, in close
        self._loop.call_soon(self._call_connection_lost, None)
      File "C:\Users\<user>\AppData\Roaming\uv\python\cpython-3.12.10-windows-x86_64-none\Lib\asyncio\base_events.py", line 799, in call_soon
        self._check_closed()
      File "C:\Users\<user>\AppData\Roaming\uv\python\cpython-3.12.10-windows-x86_64-none\Lib\asyncio\base_events.py", line 545, in _check_closed
        raise RuntimeError('Event loop is closed')
    RuntimeError: Event loop is closed
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconcurrency/asyncioIssues related to concurrency (asyncio-only)externalRoot cause pending resolution in an external dependency

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions