aio-libs/aiohttp · error · ValueError
keepalive_timeout cannot be set if force_close is True
Error message
keepalive_timeout cannot be set if force_close is True
What it means
Raised by BaseConnector.__init__ when the caller sets both `force_close=True` (no connection reuse) and an explicit `keepalive_timeout`. The two are contradictory: keepalive_timeout only matters when connections are pooled, but force_close disables pooling entirely, so aiohttp refuses the silent no-op. Passing `sentinel` or `None` is allowed because those mean 'unset'.
Source
Thrown at aiohttp/connector.py:339
# abort transport after 2 seconds (cleanup broken connections)
_cleanup_closed_period = 2.0
allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET
def __init__(
self,
*,
keepalive_timeout: _SENTINEL | None | float = sentinel,
force_close: bool = False,
limit: int = 100,
limit_per_host: int = 0,
enable_cleanup_closed: bool = False,
timeout_ceil_threshold: float = 5,
) -> None:
if force_close:
if keepalive_timeout is not None and keepalive_timeout is not sentinel:
raise ValueError(
"keepalive_timeout cannot be set if force_close is True"
)
else:
if keepalive_timeout is sentinel:
keepalive_timeout = 15.0
self._timeout_ceil_threshold = timeout_ceil_threshold
loop = asyncio.get_running_loop()
self._closed = False
if loop.get_debug():
self._source_traceback = traceback.extract_stack(sys._getframe(1))
# Connection pool of reusable connections.
# We use a deque to store connections because it has O(1) popleft()
# and O(1) append() operations to implement a FIFO queue.
self._conns: defaultdict[View on GitHub (pinned to c0ef574e29)
Solutions
- Drop the keepalive_timeout argument when force_close=True.
- Or set force_close=False (the default) and keep the keepalive_timeout.
- Audit the connector factory / fixtures that build connectors for tests.
Example fix
# before connector = aiohttp.TCPConnector(force_close=True, keepalive_timeout=30) # after connector = aiohttp.TCPConnector(force_close=True)
Defensive patterns
Strategy: validation
Validate before calling
def build_connector(force_close: bool, keepalive_timeout=None):
if force_close and keepalive_timeout is not None:
raise ValueError('do not set keepalive_timeout with force_close=True')
return aiohttp.TCPConnector(force_close=force_close, keepalive_timeout=keepalive_timeout) Try / catch
try:
connector = aiohttp.TCPConnector(force_close=True, keepalive_timeout=30)
except ValueError:
connector = aiohttp.TCPConnector(force_close=True) Prevention
- Make force_close and keepalive_timeout mutually exclusive in your connector factory.
- Centralize connector construction in one helper so config drift is caught in one place.
- Add a unit test that asserts valid combinations build successfully.
When it happens
Trigger: Constructing a connector like `TCPConnector(force_close=True, keepalive_timeout=30)` (or via `ClientSession(connector=...)`).
Common situations: Copy-pasting a config block that set keepalive_timeout then flipping force_close on. Tuning for a flaky server by adding force_close without removing the timeout. Inheriting connector kwargs from a shared helper that always sets both.
Related errors
- ssl should be SSLContext, Fingerprint, or bool, got {ssl!r}
- either both host and port or none of them are allowed
- {host} - is not a canonical IPv4 address
- Compress wbits must between 9 and 15, zlib does not support
- base_url must have a trailing '/'
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/1ae1b10596d34584.json.
Report an issue: GitHub.