{"id":"8d959723ff3a5004","repo":"aio-libs/aiohttp","slug":"access-log-class-must-be-subclass-of-aiohttp-abc-a","errorCode":null,"errorMessage":"access_log_class must be subclass of aiohttp.abc.AbstractAccessLogger, got {}","messagePattern":"access_log_class must be subclass of aiohttp\\.abc\\.AbstractAccessLogger, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_runner.py","lineNumber":450,"sourceCode":"        self,\n        app: Application,\n        *,\n        handle_signals: bool = False,\n        access_log_class: type[AbstractAccessLogger] = AccessLogger,\n        **kwargs: Any,\n    ) -> None:\n        if not isinstance(app, Application):\n            raise TypeError(\n                f\"The first argument should be web.Application instance, got {app!r}\"\n            )\n        kwargs[\"access_log_class\"] = access_log_class\n\n        if app._handler_args:\n            for k, v in app._handler_args.items():\n                kwargs[k] = v\n\n        if not issubclass(kwargs[\"access_log_class\"], AbstractAccessLogger):\n            raise TypeError(\n                \"access_log_class must be subclass of \"\n                \"aiohttp.abc.AbstractAccessLogger, got {}\".format(\n                    kwargs[\"access_log_class\"]\n                )\n            )\n\n        super().__init__(handle_signals=handle_signals, **kwargs)\n        self._app = app\n\n    @property\n    def app(self) -> Application:\n        return self._app\n\n    async def shutdown(self) -> None:\n        await self._app.shutdown()\n\n    async def _make_server(self) -> Server[Request]:\n        self._app.on_startup.freeze()","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_runner.py#L432-L468","documentation":"Raised as TypeError by AppRunner.__init__ when the access_log_class argument is not a subclass of aiohttp.abc.AbstractAccessLogger. The runner uses this class to instantiate the per-request access logger, so anything else (a function, a logging.Logger, a str class name) would fail at request time; the subclass check guards it at startup.","triggerScenarios":"Passing access_log_class=some_function, access_log_class=logging.Logger, or a class that does not inherit from aiohttp.abc.AbstractAccessLogger to web.AppRunner(app, access_log_class=...). Also when passing the class name as a string instead of the class object.","commonSituations":"Migrating from older aiohttp where a plain callable was accepted; copying a tutorial that passes a logging.Logger; intending to disable logging by passing None (None is not a subclass and raises); providing a custom logger class that forgot to subclass AbstractAccessLogger.","solutions":["Subclass aiohttp.abc.AbstractAccessLogger and pass that class object: class MyLogger(AbstractAccessLogger): def log(self, request, response, time): ...; AppRunner(app, access_log_class=MyLogger).","To disable access logging, pass access_log_class=None is NOT valid — instead pass access_log_class=aiohttp.abc.AbstractAccessLogger is also wrong; set the runner/server with access_log=None via the Application's handler args or omit logging.","Pass the class itself, not an instance and not a string name.","If you only want standard logging, omit access_log_class to use the default AccessLogger."],"exampleFix":"# before\nAppRunner(app, access_log_class=logging.Logger)\n\n# after\nfrom aiohttp.abc import AbstractAccessLogger\n\nclass MyLogger(AbstractAccessLogger):\n    def log(self, request, response, time):\n        self.logger.info(f\"{request.method} {request.path}\")\n\nAppRunner(app, access_log_class=MyLogger)","handlingStrategy":"type-guard","validationCode":"from aiohttp.abc import AbstractAccessLogger\n\ndef validate_log_class(cls):\n    assert isinstance(cls, type) and issubclass(cls, AbstractAccessLogger), \\\n        f\"access_log_class must subclass AbstractAccessLogger, got {cls!r}\"\n    return cls","typeGuard":"from aiohttp.abc import AbstractAccessLogger\n\ndef is_access_logger(cls) -> bool:\n    return isinstance(cls, type) and issubclass(cls, AbstractAccessLogger)","tryCatchPattern":"try:\n    runner = web.AppRunner(app, access_log_class=cls)\nexcept TypeError as e:\n    raise SystemExit(f\"Bad access_log_class: {e}\") from e","preventionTips":["Always subclass aiohttp.abc.AbstractAccessLogger for custom loggers.","Pass the class object, never an instance or string.","Omit access_log_class to use the safe default AccessLogger."],"tags":["aiohttp","web-server","logging","type-error","app-runner"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}