The Fix
Fixes the issue of error messages being swallowed in AsyncResolver by correctly raising OSError with the appropriate arguments.
Based on closed aio-libs/aiohttp issue #9447 · PR/commit linked
Production note: Watch p95/p99 latency and retry volume; timeouts can turn into retry storms and duplicate side-effects.
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+Fixed error messages from :py:class:`~aiohttp.resolver.AsyncResolver` being swallowed -- by :user:`bdraco`.
diff --git a/aiohttp/resolver.py b/aiohttp/resolver.py
index daa90b828c6..1025df06398 100644
import aiohttp
import asyncio
import datetime
import logging
async def fetch(client):
timeout = aiohttp.ClientTimeout(total=10)
async with client.head("https://checkonline.home-assistant.io/online.txt", timeout=timeout) as resp:
assert resp.status == 200
return await resp.text()
async def main():
async with aiohttp.ClientSession() as client:
while True:
print(datetime.datetime.now())
try:
html = await fetch(client)
print(html)
except Exception as e:
logging.exception(e)
logging.basicConfig(
format='%(asctime)s %(levelname)s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S'
)
asyncio.run(main())
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Apply the official fix\nFixes the issue of error messages being swallowed in AsyncResolver by correctly raising OSError with the appropriate arguments.\nWhen NOT to use: This fix should not be applied if the application relies on the previous error handling behavior.\n\n
Why This Fix Works in Production
- Trigger: resp = await self._resolver.getaddrinfo(
- Mechanism: The OSError was incorrectly raised without the appropriate errno, causing error messages to be swallowed
- If left unfixed, tail latency can spike under load and surface as timeouts/retries (amplifying incident impact).
Why This Breaks in Prod
- Shows up under Python 3.12 in real deployments (not just unit tests).
- The OSError was incorrectly raised without the appropriate errno, causing error messages to be swallowed
- Surfaces as: Traceback (most recent call last):
Proof / Evidence
- GitHub issue: #9447
- Fix PR: https://github.com/aio-libs/aiohttp/pull/9451
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.80
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.35
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“the missing errors are fixed in https://github.com/aio-libs/aiohttp/pull/9451”
“Changing the host to xcheckonline.home-assistant.io is enough to show its always swallowing it”
“It looks like strerror is never set from aiodns”
“we raise OSError(msg) but the first arg to OSError is the errno So it should be OSError(None, msg)”
Failure Signature (Search String)
- resp = await self._resolver.getaddrinfo(
Error Message
Stack trace
Error Message
-------------
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/aiohttp/resolver.py", line 105, in resolve
resp = await self._resolver.getaddrinfo(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
aiodns.error.DNSError: (12, 'Timeout while contacting DNS servers')
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/aiohttp/connector.py", line 1294, in _create_direct_connection
hosts = await self._resolve_host(host, port, traces=traces)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiohttp/connector.py", line 945, in _resolve_host
return await asyncio.shield(resolved_host_task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiohttp/connector.py", line 982, in _resolve_host_with_throttle
addrs = await self._resolver.resolve(host, port, family=self._family)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiohttp/resolver.py", line 114, in resolve
raise OSError(msg) from exc
OSError: Timeout while contacting DNS servers
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/tmp/test3.py", line 16, i
... (truncated) ...
Minimal Reproduction
import aiohttp
import asyncio
import datetime
import logging
async def fetch(client):
timeout = aiohttp.ClientTimeout(total=10)
async with client.head("https://checkonline.home-assistant.io/online.txt", timeout=timeout) as resp:
assert resp.status == 200
return await resp.text()
async def main():
async with aiohttp.ClientSession() as client:
while True:
print(datetime.datetime.now())
try:
html = await fetch(client)
print(html)
except Exception as e:
logging.exception(e)
logging.basicConfig(
format='%(asctime)s %(levelname)s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S'
)
asyncio.run(main())
Environment
- Python: 3.12
What Broke
Users experience silent failures when DNS resolution times out, leading to confusion and unhandled exceptions.
Why It Broke
The OSError was incorrectly raised without the appropriate errno, causing error messages to be swallowed
Fix Options (Details)
Option A — Apply the official fix
Fixes the issue of error messages being swallowed in AsyncResolver by correctly raising OSError with the appropriate arguments.
Fix reference: https://github.com/aio-libs/aiohttp/pull/9451
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be applied if the application relies on the previous error handling behavior.
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
- 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.
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.