From 6a0b68cacf35af2576cb73d5f71731a2ea050eaf Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Thu, 10 Sep 2026 09:21:40 +0200 Subject: [PATCH 1/2] Give the Windows IO backend the error messages its siblings have wait_readable / wait_writable raised a bare BusyResourceError, and notify_closing a bare ClosedResourceError. The epoll and kqueue backends describe both. _io_windows already passes a message for the lpOverlapped case, so it was inconsistent with itself too. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011M5uTyCU4WcNTsPvGrErDo --- src/trio/_core/_io_windows.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 7b789c3dec..99f31aea0a 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -740,7 +740,9 @@ async def _afd_poll(self, sock: _HasFileNo | int, mode: str) -> None: waiters = AFDWaiters() self._afd_waiters[base_handle] = waiters if getattr(waiters, mode) is not None: - raise _core.BusyResourceError + raise _core.BusyResourceError( + "another task is already reading / writing this socket", + ) setattr(waiters, mode, _core.current_task()) # Could potentially raise if the handle is somehow invalid; that's OK, # we let it escape. @@ -822,7 +824,10 @@ def notify_closing(self, handle: Handle | int | _HasFileNo) -> None: handle = _get_base_socket(handle) waiters = self._afd_waiters.get(handle) if waiters is not None: - wake_all(waiters, _core.ClosedResourceError()) + wake_all( + waiters, + _core.ClosedResourceError("another task closed this socket"), + ) self._refresh_afd(handle) ################################################################ From 1e5ef5f009349425674b14d713e219bb62308222 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Thu, 10 Sep 2026 09:22:07 +0200 Subject: [PATCH 2/2] Add newsfragment for 3509 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011M5uTyCU4WcNTsPvGrErDo --- newsfragments/3509.bugfix.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 newsfragments/3509.bugfix.rst diff --git a/newsfragments/3509.bugfix.rst b/newsfragments/3509.bugfix.rst new file mode 100644 index 0000000000..2966f4706f --- /dev/null +++ b/newsfragments/3509.bugfix.rst @@ -0,0 +1,4 @@ +On Windows, :func:`trio.lowlevel.wait_readable`, :func:`trio.lowlevel.wait_writable` +and :func:`trio.lowlevel.notify_closing` raised ``BusyResourceError`` and +``ClosedResourceError`` without any message. They now explain themselves, as they +already did on the epoll and kqueue backends.