{"id":"bedb2eef88a49a8e","repo":"aio-libs/aiohttp","slug":"connector-is-closed","errorCode":null,"errorMessage":"Connector is closed.","messagePattern":"Connector is closed\\.","errorType":"exception","errorClass":"ClientConnectionError","httpStatus":null,"severity":"error","filePath":"aiohttp/connector.py","lineNumber":699,"sourceCode":"\n            try:\n                # Traces are done inside the try block to ensure that the\n                # that the placeholder is still cleaned up if an exception\n                # is raised.\n                if traces:\n                    for trace in traces:\n                        await trace.send_connection_create_start()\n                proto = await self._create_connection(req, traces, timeout)\n                if traces:\n                    for trace in traces:\n                        await trace.send_connection_create_end()\n            except BaseException:\n                self._release_acquired(key, placeholder)\n                raise\n            else:\n                if self._closed:\n                    proto.close()\n                    raise ClientConnectionError(\"Connector is closed.\")\n\n        # The connection was successfully created, drop the placeholder\n        # and add the real connection to the acquired set. There should\n        # be no awaits after the proto is added to the acquired set\n        # to ensure that the connection is not left in the acquired set\n        # on cancellation.\n        self._acquired.remove(placeholder)\n        self._acquired.add(proto)\n        if self._limit_per_host:\n            acquired_per_host = self._acquired_per_host[key]\n            acquired_per_host.remove(placeholder)\n            acquired_per_host.add(proto)\n        return Connection(self, key, proto, self._loop)\n\n    async def _wait_for_available_connection(\n        self, key: \"ConnectionKey\", traces: list[\"Trace\"]\n    ) -> None:\n        \"\"\"Wait for an available connection slot.\"\"\"","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/connector.py#L681-L717","documentation":"Raised inside BaseConnector.connect() after _create_connection has succeeded, if self._closed became True during the await (another task called connector.close()). The freshly opened proto is closed and the request aborted with ClientConnectionError to avoid handing out a connection from a pool that is being torn down. This is a race between shutdown and a concurrent request.","triggerScenarios":"One coroutine calls `await connector.close()` (or closes the ClientSession that owns the connector) while another is mid-`await session.get(...)` and has just finished establishing the TCP connection.","commonSituations":"Application shutdown ordering: closing the session while in-flight requests are still settling. Fixtures that close the connector in teardown concurrently with the test making a final call. Cancellation paths where cleanup runs before pending ops drain.","solutions":["Order shutdown: await all in-flight requests (or cancel and await them) before calling session/connector.close().","Use a lifespan/guard flag and reject new requests once shutdown has begun, rather than racing close().","If seen during tests, ensure the test fixture closes the session after the request completes."],"exampleFix":"# before\nasync def main():\n    task = asyncio.create_task(session.get(url))\n    await session.close()  # races with task\n    return await task\n# after\nasync def main():\n    task = asyncio.create_task(session.get(url))\n    resp = await task\n    await session.close()\n    return resp","handlingStrategy":"validation","validationCode":"def is_connector_open(connector) -> bool:\n    return not connector.closed","typeGuard":null,"tryCatchPattern":"from aiohttp import ClientConnectionError\ntry:\n    resp = await session.get(url)\nexcept ClientConnectionError as e:\n    if 'Connector is closed' in str(e):\n        # session was shut down concurrently; recreate or give up\n        ...\n    raise","preventionTips":["Use an async context manager (`async with aiohttp.ClientSession() as s:`) so lifetime is bounded.","Await all in-flight tasks before calling close() on the session/connector.","Track outstanding requests with a counter and gate close() on it reaching zero."],"tags":["connector","lifecycle","race","shutdown"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}