Skip to content

Tasks stuck in cancelling state – idle_conn_watch_task never finishes under cancellation on Windows #293

@thomas-xin

Description

@thomas-xin

Subject

This is a followup to our conversation at thomas-xin/Miza@d1a9573#r165312062 - While the original bug appears to be fixed, the current state of the library appears to very occasionally cause deadlocks instead.

Environment

OS Windows-11-10.0.26220-SP0
Python 3.13.8
OpenSSL 3.0.18 30 Sep 2025
urllib3 2.14.906

Steps to Reproduce

I believe I can't give exact steps to reproduce, as this is an inconsistent issue that gradually builds up "leaked" stuck tasks as more requests are performed. The only thing that remains consistent is that it occurs with session reuse.
To be clear, I am invoking the request via niquests and not urllib3-future directly, but I have traced the problematic sections to this library, as seen below. Note that due to the nature of this problem, there is no naturally occurring exception or traceback to be shown.

Expected Behavior

Requests should either complete correctly, give a relevant error, or produce a timeout.
Even if timeout does not occur for any reason, it should remain cancellable at any point.

Actual Behavior

The task never finishes despite the request being given a timeout, remaining in pending state.
If wrapped with asyncio.wait_for, after that timeout expires, the task becomes "cancelling" but never exits that state either. This also can occur if the request is cancelled directly with .cancel().

When probing its properties, something similar to the following can be found:
<Task cancelling name='Task-680' coro=<idle_conn_watch_task() running at ...\Python313\site-packages\urllib3\_async\connectionpool.py:171> wait_for=<Future pending cb=[Task.task_wakeup()] created at ...\Python313\Lib\asyncio\base_events.py:459> created at ...\Python313\Lib\asyncio\tasks.py:410>

When issuing traceback.print_stack, I will typically see the following line:
File "...\Python313\site-packages\urllib3\_async\connectionpool.py", line 171, in idle_conn_watch_task await asyncio.sleep(waiting_delay)

And finally, when inspecting the .cancelling() method of the task, I will typically see a very large number in the hundreds, such as 715. This perhaps implies something is swallowing asyncio.CancelledError, however I have not been able to find the cause from the source code itself.
I hope this information is still useful, however!

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