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
AppRunner.__init__ requires its first positional argument to be an instance of aiohttp.web.Application. The constructor performs an isinstance(app, Application) check at entry and raises TypeError if it fails, because every downstream step (handler_args extraction, super().__init__ setup, self._app assignment) assumes a real Application object. Passing anything else — a string, a dict, a Router, a None — would cause cryptic AttributeError failures later, so aiohttp fails fast with a descriptive message.
Solutions
- Ensure the first argument is an instance of aiohttp.web.Application — call web.Application() to create one if needed.
- If you are passing app.router, change it to the Application instance itself.
- In tests, construct a real Application (web.Application()) rather than a mock or a bare dict.
- If subclassing Application, confirm the subclass derives from aiohttp.web.Application.
Example fix
// before runner = web.AppRunner(router) # router is app.router // after runner = web.AppRunner(app) # pass the Application instance
Defensive patterns
Strategy: type-guard
Validate before calling
from aiohttp import web
def make_runner(app) -> web.AppRunner:
if not isinstance(app, web.Application):
raise TypeError(f'Expected web.Application, got {type(app).__name__}')
return web.AppRunner(app) Type guard
from aiohttp import web
def is_application(app) -> bool:
return isinstance(app, web.Application) Try / catch
try:
runner = web.AppRunner(app)
except TypeError as e:
if 'should be web.Application' in str(e):
# log and abort startup
raise
raise Prevention
- Always construct the Application with web.Application() in the same scope where you build the runner.
- Add a startup assertion: assert isinstance(app, web.Application).
- In tests, use a factory fixture that returns a fresh web.Application().
When it happens
Trigger: Constructing AppRunner directly (AppRunner(app)) with a non-Application object: e.g. AppRunner(router), AppRunner(None), AppRunner('my-app'), or passing a sub-app (the nested Application added via add_subapp) when the outer Application is intended. Also triggered by passing an Application subclass that does not actually inherit from aiohttp.web.Application.
Common situations: Mistaking web.AppRunner for a generic runner that accepts a Router object; copy-pasting from examples that build the Application in a separate function and forgetting the call; test fixtures that return a mock or a partially-built object; refactoring that accidentally passes the app's .router attribute instead of the app itself.
Related errors
- access_log_class must be subclass of…
- aiohttp only supports http(s) proxies
- base_url must have a trailing '/'
- compress can not be set if Content-Encoding header is set
- compress must be one of True, False, 'deflate', or 'gzip'
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/a963119d0c6d6b9e.
Report an issue: GitHub.
Appendix: 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 = appView on GitHub (pinned to d041d4d0fd)