The Fix
Upgrade to version 2.0.0 or later.
Based on closed pallets/flask issue #3981 · PR/commit linked
Production note: Most teams hit this during upgrades or environment changes. Roll out with a canary and smoke critical endpoints (health, OpenAPI/docs) before 100%.
@@ -17,6 +17,12 @@ defined with ``async def`` and use ``await``.
return jsonify(data)
+.. admonition:: Using ``async`` on Windows on Python 3.8
+
+ Python 3.8 has a bug related to asyncio on Windows. If you encounter
Traceback (most recent call last):
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1953, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1454, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1452, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\greyli\...\app.py", line 318, in dispatch_request
return self.view_functions[rule.endpoint](*req.view_args.values())
File "c:\users\greyli\...\venv\lib\site-packages\flask\helpers.py", line 781, in outer
return async_to_sync(inner)(*args, **kwargs)
File "c:\users\...\venv\lib\site-packages\asgiref\sync.py", line 203, in __call__
loop_future.result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 432, in result
return self.__get_result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 388, in __get_result
raise self._exception
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "c:\users\greyli\...\venv\lib\site-packages\asgiref\sync.py", line 256, in _run_event_loop
loop.close()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\asyncio\proactor_events.py", line 679, in
close
signal.set_wakeup_fd(-1)
ValueError: set_wakeup_fd only works in main thread
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 2.0.0 or later.\nWhen NOT to use: Do not use if it changes public behavior or if the failure cannot be reproduced.\n\n
Why This Fix Works in Production
- Trigger: ValueError: set_wakeup_fd only works in main thread
- Mechanism: Added a tip for using async on Windows with Python 3.8, indicating a bug and suggesting an upgrade to Python 3.9.
- Why the fix works: Added a tip for using async on Windows with Python 3.8, indicating a bug and suggesting an upgrade to Python 3.9. (first fixed release: 2.0.0).
- If left unfixed, the same config can fail only in production (env differences), causing startup failures or partial feature outages.
Why This Breaks in Prod
- Shows up under Python 3.8 in real deployments (not just unit tests).
- Surfaces as: ValueError: set_wakeup_fd only works in main thread
Proof / Evidence
- GitHub issue: #3981
- Fix PR: https://github.com/pallets/flask/pull/3985
- First fixed release: 2.0.0
- Reproduced locally: No (not executed)
- Last verified: 2026-02-08
- Confidence: 0.85
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.23
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“> Does it work on Windows on Python 3.9? Yes, it works fine on Python 3.9.”
“I think we leave this as a bug in Python 3.8 or asgiref then, which may be fixed later. We can make a note of…”
“Sounds good. I'll make a PR for it tomorrow. Besides, we may also need to mention it in the pre-release announcement.”
Failure Signature (Search String)
- ValueError: set_wakeup_fd only works in main thread
Error Message
Stack trace
Error Message
-------------
ValueError: set_wakeup_fd only works in main thread
Stack trace
Error Message
-------------
Traceback (most recent call last):
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1953, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1454, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1452, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\greyli\...\app.py", line 318, in dispatch_request
return self.view_functions[rule.endpoint](*req.view_args.values())
File "c:\users\greyli\...\venv\lib\site-packages\flask\helpers.py", line 781, in outer
return async_to_sync(inner)(*args, **kwargs)
File "c:\users\...\venv\lib\site-packages\asgiref\sync.py", line 203, in __call__
loop_future.result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 432, in result
return self.__get_result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 388, in __get_result
raise self._exception
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "c:\users\greyli\...\venv\lib\site-packages\asgiref\sync.py", line 256, in _run_event_loop
loop.close()
File "C:\Users\g
... (truncated) ...
Minimal Reproduction
Traceback (most recent call last):
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1953, in wsgi_app
response = self.full_dispatch_request()
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1454, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\users\greyli\...\venv\lib\site-packages\flask\app.py", line 1452, in full_dispatch_request
rv = self.dispatch_request()
File "c:\users\greyli\...\app.py", line 318, in dispatch_request
return self.view_functions[rule.endpoint](*req.view_args.values())
File "c:\users\greyli\...\venv\lib\site-packages\flask\helpers.py", line 781, in outer
return async_to_sync(inner)(*args, **kwargs)
File "c:\users\...\venv\lib\site-packages\asgiref\sync.py", line 203, in __call__
loop_future.result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 432, in result
return self.__get_result()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\_base.py", line 388, in __get_result
raise self._exception
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\concurrent\futures\thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "c:\users\greyli\...\venv\lib\site-packages\asgiref\sync.py", line 256, in _run_event_loop
loop.close()
File "C:\Users\greyli\.pyenv\pyenv-win\versions\3.8.0\lib\asyncio\proactor_events.py", line 679, in
close
signal.set_wakeup_fd(-1)
ValueError: set_wakeup_fd only works in main thread
Environment
- Python: 3.8
What Broke
Users encounter a ValueError when using async functions, leading to application crashes.
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 2.0.0 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/pallets/flask/pull/3985
First fixed release: 2.0.0
Last verified: 2026-02-08. Validate in your environment.
When NOT to Use This Fix
- Do not use if it changes public behavior or if the failure cannot be reproduced.
Verify Fix
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
- Pin production dependencies and upgrade only with a reproducible test that hits the failing path.
Version Compatibility Table
| Version | Status |
|---|---|
| 2.0.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.