{"record":{"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":"exception","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/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_runner.py#L432-L468","documentation":"AppRunner.__init__ validates that access_log_class is a subclass of aiohttp.abc.AbstractAccessLogger. The check runs after kwargs are assembled (so it covers both the explicit parameter and any value injected via app._handler_args). Aiohttp needs the access logger to implement the log(request, response, time) interface defined by AbstractAccessLogger; an arbitrary class would break access logging at runtime.","triggerScenarios":"Passing access_log_class=<some_callable_or_class> where the class does not inherit from AbstractAccessLogger. Common: passing a plain function, a logging.Logger subclass, or a custom class that implements the right methods but forgot to extend the ABC. The value can also arrive indirectly through Application(handler_args={'access_log_class': ...}).","commonSituations":"Writing a custom access logger and forgetting `class MyLogger(AbstractAccessLogger)`; migrating from an older aiohttp version where the base class was named differently; passing a callable factory instead of the class itself.","solutions":["Make your custom logger inherit from aiohttp.abc.AbstractAccessLogger and implement the log(self, request, response, time) method.","If you do not need a custom logger, omit access_log_class entirely to use the default AccessLogger.","Verify the object passed is the class itself, not an instance or a function."],"exampleFix":"// before\nclass MyLogger:\n    def log(self, request, response, time): ...\nrunner = web.AppRunner(app, access_log_class=MyLogger)\n// after\nfrom aiohttp.abc import AbstractAccessLogger\nclass MyLogger(AbstractAccessLogger):\n    def log(self, request, response, time): ...\nrunner = web.AppRunner(app, access_log_class=MyLogger)","handlingStrategy":"validation","validationCode":"from aiohttp.abc import AbstractAccessLogger\n\ndef register_logger(cls):\n    if not (isinstance(cls, type) and issubclass(cls, AbstractAccessLogger)):\n        raise TypeError('access_log_class must subclass AbstractAccessLogger')\n    return cls","typeGuard":"from aiohttp.abc import AbstractAccessLogger\n\ndef is_access_logger_class(obj) -> bool:\n    return isinstance(obj, type) and issubclass(obj, AbstractAccessLogger)","tryCatchPattern":null,"preventionTips":["Always inherit from aiohttp.abc.AbstractAccessLogger when writing a custom logger.","Keep a project-level base class that extends AbstractAccessLogger and subclass from it.","Write a smoke test that instantiates AppRunner with your custom logger class."],"tags":["web-server","app-runner","access-log","type-check"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}