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

  1. Drop the keepalive_timeout argument when force_close=True.
  2. Or set force_close=False (the default) and keep the keepalive_timeout.
  3. 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

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


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/1ae1b10596d34584.json. Report an issue: GitHub.