{"id":"1ae8def7e9807e3c","repo":"aio-libs/aiohttp","slug":"only-async-functions-are-allowed-as-web-handlers","errorCode":null,"errorMessage":"Only async functions are allowed as web-handlers, got {handler!r}","messagePattern":"Only async functions are allowed as web-handlers, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_urldispatcher.py","lineNumber":175,"sourceCode":"        if expect_handler is None:\n            expect_handler = _default_expect_handler\n\n        assert inspect.iscoroutinefunction(expect_handler) or (\n            sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler)  # type: ignore[deprecated]\n        ), f\"Coroutine is expected, got {expect_handler!r}\"\n\n        method = method.upper()\n        if not HTTP_METHOD_RE.match(method):\n            raise ValueError(f\"{method} is not allowed HTTP method\")\n\n        if inspect.iscoroutinefunction(handler) or (\n            sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler)  # type: ignore[deprecated]\n        ):\n            pass\n        elif isinstance(handler, type) and issubclass(handler, AbstractView):\n            pass\n        else:\n            raise TypeError(\n                f\"Only async functions are allowed as web-handlers, got {handler!r}\"\n            )\n\n        self._method = method\n        self._handler = handler\n        self._expect_handler = expect_handler\n        self._resource = resource\n\n    @property\n    def method(self) -> str:\n        return self._method\n\n    @property\n    def handler(self) -> Handler:\n        return self._handler\n\n    @property\n    @abc.abstractmethod","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_urldispatcher.py#L157-L193","documentation":"Raised as TypeError by Route.__init__ when the handler is neither an async function (coroutine function) nor a class subclassing aiohttp.web.AbstractView. aiohttp dispatches handlers via await, so a synchronous function or a plain callable would return a non-awaitable and break the request pipeline; the check rejects it at registration time.","triggerScenarios":"Calling app.router.add_get('/x', sync_handler) where def sync_handler(request): return ... (no async). Passing a lambda, a functools.partial of a sync function, or a class instance instead of a class. Using @routes.get on a def (non-async) function.","commonSituations":"Copying Flask/FastAPI-style sync handlers into aiohttp; forgetting 'async def'; wrapping a coroutine in partial incorrectly; using class-based views but passing an instance instead of the class; refactoring that dropped the async keyword.","solutions":["Make the handler async: change 'def handler(request):' to 'async def handler(request):'.","For class-based views, subclass aiohttp.web.AbstractView and pass the class (not an instance): app.router.add_route('GET', '/', MyView).","If wrapping with functools.partial, ensure the underlying function is async.","Run a grep for route-registered handlers missing 'async def' after refactors."],"exampleFix":"# before\ndef handle(request):\n    return web.Response(text=\"hi\")\napp.router.add_get('/', handle)\n\n# after\nasync def handle(request):\n    return web.Response(text=\"hi\")\napp.router.add_get('/', handle)","handlingStrategy":"type-guard","validationCode":"import inspect\n\ndef ensure_async_handler(handler):\n    if not (inspect.iscoroutinefunction(handler) or\n            (isinstance(handler, type) and issubclass(handler, AbstractView))):\n        raise TypeError(f\"handler must be async def or AbstractView subclass: {handler!r}\")\n    return handler","typeGuard":"import inspect\nfrom aiohttp.web import AbstractView\n\ndef is_web_handler(h) -> bool:\n    return inspect.iscoroutinefunction(h) or (\n        isinstance(h, type) and issubclass(h, AbstractView)\n    )","tryCatchPattern":"try:\n    app.router.add_get(path, handler)\nexcept TypeError as e:\n    raise TypeError(f\"{handler!r} is not an async web handler: {e}\") from e","preventionTips":["Default to 'async def' for every route handler.","Add a CI grep that flags 'def ' decorators registered as routes without async.","For class-based views, subclass aiohttp.web.AbstractView."],"tags":["aiohttp","routing","async","handler","type-error"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}