The Fix
Upgrade to version 0.11.4 or later.
Based on closed Kludex/uvicorn issue #565 · PR/commit linked
Production note: Watch p95/p99 latency and retry volume; timeouts can turn into retry storms and duplicate side-effects.
@@ -13,8 +13,8 @@ def get_version(package):
Return package version as listed in `__version__` in `init.py`.
"""
- path = os.path.join(package, '__init__.py')
- init_py = open(path, 'r', encoding='utf8').read()
+ path = os.path.join(package, "__init__.py")
[2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
Traceback (most recent call last):
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
worker.init_process()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 57, in init_process
super(UvicornWorker, self).init_process()
│ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
└ <class 'uvicorn.workers.UvicornWorker'>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/workers/base.py", line 134, in init_process
self.run()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 66, in run
loop.run_until_complete(server.serve(sockets=self.sockets))
│ │ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
│ └ <uvicorn.main.Server object at 0x10bc80d90>
└ <_UnixSelectorEventLoop running=False closed=False debug=False>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
return future.result()
└ <Task finished coro=<Server.serve() done, defined at /Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-pack...
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/main.py", line 403, in serve
await self.shutdown(sockets=sockets)
│ └ [<gunicorn.sock.TCPSocket object at 0x10bc77890>]
└ <uvicorn.main.Server object at 0x10bc80d90>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/main.py", line 533, in shutdown
server.close()
└ <Server sockets=[]>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 306, in close
self._loop._stop_serving(sock)
│ └ <gunicorn.sock.TCPSocket object at 0x10bc77890>
└ <Server sockets=[]>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/selector_events.py", line 562, in _stop_serving
self._remove_reader(sock.fileno())
│ └ <gunicorn.sock.TCPSocket object at 0x10bc77890>
└ <_UnixSelectorEventLoop running=False closed=False debug=False>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/sock.py", line 38, in __getattr__
return getattr(self.sock, name)
│ └ 'fileno'
└ <gunicorn.sock.TCPSocket object at 0x10bc77890>
AttributeError: 'NoneType' object has no attribute 'fileno'
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 0.11.4 or later.\nWhen NOT to use: This fix should not be applied if the shutdown behavior is expected to change for other components.\n\n
Why This Fix Works in Production
- Trigger: [2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
- Mechanism: Reverses the order during Server.shutdown() to ensure the server is closed first, followed by a safe close of any remaining sockets.
- Why the fix works: Reverses the order during Server.shutdown() to ensure the server is closed first, followed by a safe close of any remaining sockets. (first fixed release: 0.11.4).
Why This Breaks in Prod
- Shows up under Python 3.7 in real deployments (not just unit tests).
- Surfaces as: [2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
Proof / Evidence
- GitHub issue: #565
- Fix PR: https://github.com/kludex/uvicorn/pull/566
- First fixed release: 0.11.4
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.85
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.31
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“Currently when running gunicorn + uvicorn (a suggested production deployment pattern), I get a exception on shutdown (on SIGTERM): This appears to be because sockets created by servers are explicitly closed before closing servers, however,”
Failure Signature (Search String)
- [2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
Error Message
Stack trace
Error Message
-------------
[2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
Traceback (most recent call last):
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
worker.init_process()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 57, in init_process
super(UvicornWorker, self).init_process()
│ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
└ <class 'uvicorn.workers.UvicornWorker'>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/workers/base.py", line 134, in init_process
self.run()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 66, in run
loop.run_until_complete(server.serve(sockets=self.sockets))
│ │ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
│ └ <uvicorn.main.Server object at 0x10bc80d90>
└ <_UnixSelectorEventLoop running=False closed=False debug=False>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 579, in run_u
... (truncated) ...
Minimal Reproduction
[2020-02-04 17:40:31 -0500] [37823] [ERROR] Exception in worker process
Traceback (most recent call last):
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
worker.init_process()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 57, in init_process
super(UvicornWorker, self).init_process()
│ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
└ <class 'uvicorn.workers.UvicornWorker'>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/workers/base.py", line 134, in init_process
self.run()
└ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/workers.py", line 66, in run
loop.run_until_complete(server.serve(sockets=self.sockets))
│ │ └ <uvicorn.workers.UvicornWorker object at 0x10b9f9110>
│ └ <uvicorn.main.Server object at 0x10bc80d90>
└ <_UnixSelectorEventLoop running=False closed=False debug=False>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
return future.result()
└ <Task finished coro=<Server.serve() done, defined at /Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-pack...
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/main.py", line 403, in serve
await self.shutdown(sockets=sockets)
│ └ [<gunicorn.sock.TCPSocket object at 0x10bc77890>]
└ <uvicorn.main.Server object at 0x10bc80d90>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/uvicorn/main.py", line 533, in shutdown
server.close()
└ <Server sockets=[]>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 306, in close
self._loop._stop_serving(sock)
│ └ <gunicorn.sock.TCPSocket object at 0x10bc77890>
└ <Server sockets=[]>
File "/Users/wagoodman/.pyenv/versions/3.7.4/lib/python3.7/asyncio/selector_events.py", line 562, in _stop_serving
self._remove_reader(sock.fileno())
│ └ <gunicorn.sock.TCPSocket object at 0x10bc77890>
└ <_UnixSelectorEventLoop running=False closed=False debug=False>
File "/Users/wagoodman/.pyenv/versions/3.7.4/envs/venv374/lib/python3.7/site-packages/gunicorn/sock.py", line 38, in __getattr__
return getattr(self.sock, name)
│ └ 'fileno'
└ <gunicorn.sock.TCPSocket object at 0x10bc77890>
AttributeError: 'NoneType' object has no attribute 'fileno'
Environment
- Python: 3.7
What Broke
Exceptions occurred on shutdown when using gunicorn with uvicorn, leading to potential service disruptions.
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.11.4 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/kludex/uvicorn/pull/566
First fixed release: 0.11.4
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be applied if the shutdown behavior is expected to change for other components.
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
- Add a TLS smoke test that performs a real handshake in CI (include CA bundle validation and hostname checks).
- Alert on handshake failures by error string and endpoint to catch cert/CA changes quickly.
- Make timeouts explicit and test them (unit + integration) to avoid silent behavior changes.
- Instrument retries (attempt count + reason) and alert on spikes to catch dependency slowdowns.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.11.4 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.