{"id":"aac0922c4ae7ebc4","repo":"aio-libs/aiohttp","slug":"call-runner-setup-before-making-a-site","errorCode":null,"errorMessage":"Call runner.setup() before making a site","messagePattern":"Call runner\\.setup\\(\\) before making a site","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_runner.py","lineNumber":103,"sourceCode":"    code = 1\n\n\ndef _raise_graceful_exit() -> None:\n    raise GracefulExit()\n\n\nclass BaseSite(ABC):\n    __slots__ = (\"_runner\", \"_ssl_context\", \"_backlog\", \"_server\")\n\n    def __init__(\n        self,\n        runner: \"BaseRunner[Any]\",\n        *,\n        ssl_context: SSLContext | None = None,\n        backlog: int = 128,\n    ) -> None:\n        if runner.server is None:\n            raise RuntimeError(\"Call runner.setup() before making a site\")\n        self._runner = runner\n        self._ssl_context = ssl_context\n        self._backlog = backlog\n        self._server: asyncio.Server | None = None\n\n    @property\n    @abstractmethod\n    def name(self) -> str:\n        \"\"\"Return the name of the site (e.g. a URL).\"\"\"\n\n    @abstractmethod\n    async def start(self) -> None:\n        self._runner._reg_site(self)\n\n    async def stop(self) -> None:\n        self._runner._check_site(self)\n        if self._server is not None:  # Maybe not started yet\n            self._server.close()","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_runner.py#L85-L121","documentation":"BaseSite.__init__ requires runner.server to be non-None (line 102-103). runner.server is only set after await runner.setup() runs _make_server (line 345). Constructing a TCPSite/UnixSite/SockSite/NamedPipeSite before setup() raises RuntimeError.","triggerScenarios":"Creating `site = TCPSite(runner, ...)` before calling `await runner.setup()`, or forgetting the setup() call entirely in the startup sequence.","commonSituations":"Bootstrapping an aiohttp app with AppRunner/ServerRunner; reordering startup code; copy-paste that dropped the setup() line.","solutions":["Always call `await runner.setup()` before constructing any site.","Order your startup: runner = AppRunner(app); await runner.setup(); site = TCPSite(runner, ...); await site.start().","Use web.AppRunner together with aiohttp.web.run_app to avoid manual ordering."],"exampleFix":"# before\nrunner = AppRunner(app)\nsite = TCPSite(runner, '0.0.0.0', 8080)  # raises RuntimeError\nawait runner.setup()\n\n# after\nrunner = AppRunner(app)\nawait runner.setup()\nsite = TCPSite(runner, '0.0.0.0', 8080)\nawait site.start()","handlingStrategy":"validation","validationCode":"async def make_site(runner, *site_args, **site_kw):\n    if runner.server is None:\n        await runner.setup()\n    from aiohttp.web import TCPSite  # or chosen site type\n    return TCPSite(runner, *site_args, **site_kw)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always `await runner.setup()` before constructing any site.","Write a startup helper that enforces the runner->setup->site->start order.","Use aiohttp.web.run_app for simple cases to avoid manual ordering."],"tags":["server","lifecycle","runner","site","startup"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}