aio-libs/aiohttp · error · ClientConnectionError
Connector is closed
Error message
Connector is closed
What it means
Raised by TCPConnector._resolve_host() when DNS caching is disabled (`use_dns_cache=False`) and the connector is already closed at the moment a fresh resolver call would be made. Distinct from [85] (which fires after the connection is built) - this one fires earlier, before any DNS lookup, when there is no cache to fall back on.
Source
Thrown at aiohttp/connector.py:1149
raise InvalidUrlClientError(host, "is not a canonical IPv4 address")
return [
{
"hostname": host,
"host": host,
"port": port,
"family": self._family,
"proto": 0,
"flags": 0,
}
]
if not self._use_dns_cache:
if traces:
for trace in traces:
await trace.send_dns_resolvehost_start(host)
if self._closed:
raise ClientConnectionError("Connector is closed")
res = await self._resolver.resolve(host, port, family=self._family)
if traces:
for trace in traces:
await trace.send_dns_resolvehost_end(host)
return res
key = (host, port)
if key in self._cached_hosts and not self._cached_hosts.expired(key):
# get result early, before any await (#4014)
result = self._cached_hosts.next_addrs(key)
if traces:
for trace in traces:
await trace.send_dns_cache_hit(host)
return resultView on GitHub (pinned to c0ef574e29)
Solutions
- Ensure the connector/session lifetime outlives every request that uses it.
- Await in-flight requests before calling `await session.close()`.
- If you disabled the cache for testing, re-enable it or replace the resolver with a fake so no real lookup is attempted after close.
Example fix
# before
connector = aiohttp.TCPConnector(use_dns_cache=False)
session = aiohttp.ClientSession(connector=connector)
# later, after close():
await session.get(url) # -> Connector is closed
# after
# keep the session open for the duration of all requests
async with session.get(url) as resp:
...
await session.close() Defensive patterns
Strategy: validation
Validate before calling
def can_resolve(connector) -> bool:
return not connector.closed Try / catch
from aiohttp import ClientConnectionError
try:
await session.get(url)
except ClientConnectionError as e:
if str(e) == 'Connector is closed':
# recreate session/connector
...
raise Prevention
- Keep the session/connector alive for the full lifetime of all requests when use_dns_cache=False.
- In tests, replace the resolver with a stub rather than relying on closing the connector to 'stop' DNS.
- Add a shutdown barrier that awaits outstanding requests before close().
When it happens
Trigger: A connector built with `use_dns_cache=False` (or cleared) has had close() called, then a request tries to resolve a host that is not cached.
Common situations: Application shutdown racing with in-flight requests on a no-cache connector. Tests that disable DNS caching and tear down the connector between calls. Background tasks outliving the session.
Related errors
- Connector is closed.
- either both host and port or none of them are allowed
- Multiple errors on cleanup stage
- Site {site} is not registered in runner {self}
- Cannot write to closing transport
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/95d2e283c018ceee.json.
Report an issue: GitHub.