aio-libs/aiohttp · error · TypeError

The first argument should be web.Application instance, got {

Error message

The first argument should be web.Application instance, got {app!r}

What it means

Raised as TypeError by AppRunner.__init__ when the first positional argument is not an instance of aiohttp.web.Application. The runner needs a real Application to bind its request factory, startup/shutdown signals, and frozen router, so a non-Application object (a router, a dict, None, an Application subclass instance that failed import, etc.) cannot be accepted. The check happens before any server wiring, so it fails fast at construction time.

Source

Thrown at aiohttp/web_runner.py:440

    async def _cleanup_server(self) -> None:
        pass


class AppRunner(BaseRunner[Request]):
    """Web Application runner"""

    __slots__ = ("_app",)

    def __init__(
        self,
        app: Application,
        *,
        handle_signals: bool = False,
        access_log_class: type[AbstractAccessLogger] = AccessLogger,
        **kwargs: Any,
    ) -> None:
        if not isinstance(app, Application):
            raise TypeError(
                f"The first argument should be web.Application instance, got {app!r}"
            )
        kwargs["access_log_class"] = access_log_class

        if app._handler_args:
            for k, v in app._handler_args.items():
                kwargs[k] = v

        if not issubclass(kwargs["access_log_class"], AbstractAccessLogger):
            raise TypeError(
                "access_log_class must be subclass of "
                "aiohttp.abc.AbstractAccessLogger, got {}".format(
                    kwargs["access_log_class"]
                )
            )

        super().__init__(handle_signals=handle_signals, **kwargs)
        self._app = app

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Pass the actual aiohttp.web.Application instance: AppRunner(app) where app = web.Application().
  2. If using an app factory, call it first: app = await factory(); runner = web.AppRunner(app).
  3. Ensure only one aiohttp version is installed (pip show aiohttp, resolve duplicate installs) so isinstance identity holds.
  4. Check for None returns from your app builder before constructing the runner.

Example fix

# before
runner = web.AppRunner(app.router)

# after
runner = web.AppRunner(app)
Defensive patterns

Strategy: type-guard

Validate before calling

from aiohttp import web

def make_runner(app):
    assert isinstance(app, web.Application), f"expected Application, got {type(app)}"
    return web.AppRunner(app)

Type guard

from aiohttp import web
import aiohttp.web as webmod

def is_application(app) -> bool:
    return isinstance(app, webmod.Application)

Try / catch

try:
    runner = web.AppRunner(app)
except TypeError as e:
    raise SystemExit(f"Invalid app passed to AppRunner: {e}") from e

Prevention

When it happens

Trigger: Calling aiohttp.web.AppRunner(some_object) where some_object is not an Application — e.g. passing a Router, a raw coroutine, a port number, or None. Also triggered by passing an Application from a different aiohttp install whose class identity differs (isinstance fails across module re-imports).

Common situations: Confusing AppRunner with web.AppRunner usage in tutorials; passing app.router instead of app; passing the handler coroutine instead of the app; virtualenv/conda mixing two aiohttp versions so isinstance(app, Application) is False; partially-initialized app from a factory that returned None.

Related errors


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