fix: guard against proactor accept-loop race on Windows (Python 3.14+)#2
Merged
PolyphonyRequiem merged 1 commit intoinstall-combinedfrom Apr 24, 2026
Merged
Conversation
On Windows with Python 3.14+, the proactor event loop's accept callback can fire after Server.close() sets _sockets = None during shutdown, causing an AssertionError in base_events.py:_attach that crashes the workflow process. Fix: - Add _guarded_serve() wrapper that catches AssertionError when the uvicorn server is in shutdown state (should_exit = True) - Install a custom event-loop exception handler during server lifetime that suppresses the same race when it surfaces through callbacks - _is_proactor_shutdown_race() validates: AssertionError type, server shutdown state, and asyncio-originating traceback frames - Restore original exception handler in stop() The guard is narrowly scoped: only AssertionError during server shutdown is suppressed. All other exceptions delegate to the original handler. Tests: 9 new tests covering the race detection, exception handler delegation, guarded serve behavior, and edge cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
Web dashboard crashes with
AssertionErrorin Python 3.14 asyncio proactor event loop on Windows when the server accepts a new connection during shutdown.Root cause: The proactor accept callback fires after
Server.close()sets_sockets = None— a race between the shutdown path and the accept loop.Fix
Two-layer guard, both narrowly scoped to only suppress
AssertionErrorwhen the uvicorn server is in shutdown state (should_exit = True):_guarded_serve()— wrapsserver.serve()to catch the error if it propagates through the coroutine chain_is_proactor_shutdown_race()validates: AssertionError type, server shutdown state, and asyncio-originating traceback frames. The original exception handler is saved and restored instop().Why not a separate thread?
Considered running uvicorn in a dedicated thread with a selector event loop, but cross-thread communication would break existing engine contracts (asyncio.Event/Queue used by workflow engine). Much higher complexity for the same outcome.
Tests
9 new tests covering race detection, exception handler delegation, guarded serve behavior, and edge cases. All 58 server tests pass.