aio-libs/aiohttp · error · RuntimeError

Site {site} is not registered in runner {self}

Error message

Site {site} is not registered in runner {self}

What it means

BaseRunner._check_site (line 391-393) is called by BaseSite.stop() (line 119). If the site is not in the runner's _sites list (i.e. it was never registered/started, or already unregistered), stop() raises RuntimeError rather than silently no-oping.

Source

Thrown at aiohttp/web_runner.py:393

                # remove_signal_handler is not implemented on Windows
                pass

    @abstractmethod
    async def _make_server(self) -> Server[_Request]:
        """Return a new server for the runner to serve requests."""

    @abstractmethod
    async def _cleanup_server(self) -> None:
        """Run any cleanup steps after the server is shutdown."""

    def _reg_site(self, site: BaseSite) -> None:
        if site in self._sites:
            raise RuntimeError(f"Site {site} is already registered in runner {self}")
        self._sites.append(site)

    def _check_site(self, site: BaseSite) -> None:
        if site not in self._sites:
            raise RuntimeError(f"Site {site} is not registered in runner {self}")

    def _unreg_site(self, site: BaseSite) -> None:
        if site not in self._sites:
            raise RuntimeError(f"Site {site} is not registered in runner {self}")
        self._sites.remove(site)


class ServerRunner(BaseRunner[BaseRequest]):
    """Low-level web server runner"""

    __slots__ = ("_web_server",)

    def __init__(
        self,
        web_server: Server[BaseRequest],
        *,
        handle_signals: bool = False,
        **kwargs: Any,

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Only call stop() on sites you successfully started (track a started flag).
  2. Guard with a check: if site in runner.sites: await site.stop().
  3. Let runner.cleanup() handle stopping all registered sites instead of manual stop().

Example fix

# before
site = TCPSite(runner, '0.0.0.0', 8080)
# start() never awaited
await site.stop()  # raises RuntimeError (not registered)

# after
site = TCPSite(runner, '0.0.0.0', 8080)
await site.start()
await site.stop()
Defensive patterns

Strategy: validation

Validate before calling

async def safe_stop(site, runner):
    if site in runner.sites:
        await site.stop()

Prevention

When it happens

Trigger: Calling `await site.stop()` on a site that was never started (start() registers it), or stopping a site twice (after stop() the first time does not auto-unregister, but if cleanup ran it would).

Common situations: Cleanup/finally blocks that call stop() unconditionally even when start() failed or never ran; shutdown code re-stopping sites.

Related errors


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