{"record":{"id":"dc5170ebea3bea22","repo":"aio-libs/aiohttp","slug":"url-for-is-not-supported-by-sub-application-roo","errorCode":null,"errorMessage":".url_for() is not supported by sub-application root","messagePattern":"\\.url_for\\(\\) is not supported by sub-application root","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_urldispatcher.py","lineNumber":729,"sourceCode":"        super().__init__(prefix)\n        self._app = app\n        self._add_prefix_to_resources(prefix)\n\n    def add_prefix(self, prefix: str) -> None:\n        super().add_prefix(prefix)\n        self._add_prefix_to_resources(prefix)\n\n    def _add_prefix_to_resources(self, prefix: str) -> None:\n        router = self._app.router\n        for resource in router.resources():\n            # Since the canonical path of a resource is about\n            # to change, we need to unindex it and then reindex\n            router.unindex_resource(resource)\n            resource.add_prefix(prefix)\n            router.index_resource(resource)\n\n    def url_for(self, *args: str, **kwargs: str) -> URL:\n        raise RuntimeError(\".url_for() is not supported by sub-application root\")\n\n    def get_info(self) -> _InfoDict:\n        return {\"app\": self._app, \"prefix\": self._prefix}\n\n    async def resolve(self, request: Request) -> _Resolve:\n        match_info = await self._app.router.resolve(request)\n        match_info.add_app(self._app)\n        if isinstance(match_info.http_exception, HTTPMethodNotAllowed):\n            methods = match_info.http_exception.allowed_methods\n        else:\n            methods = set()\n        return match_info, methods\n\n    def __len__(self) -> int:\n        return len(self._app.router.routes())\n\n    def __iter__(self) -> Iterator[AbstractRoute]:\n        return iter(self._app.router.routes())","sourceCodeStart":711,"sourceCodeEnd":747,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_urldispatcher.py#L711-L747","documentation":"PrefixResource (the resource type used as the root of a sub-application added via add_subapp) does not support url_for(), because a sub-app root has no single canonical URL — the sub-app's own resources have URLs, but the mount prefix itself does not. Calling url_for() on it raises RuntimeError to signal this is a logical misuse.","triggerScenarios":"Obtaining the resource for a sub-app mount point (e.g. app.router.add_subapp('/api', sub_app) returns a PrefixResource) and then calling .url_for() on that resource. Code that generically iterates resources and calls url_for() on each will hit this.","commonSituations":"Generic URL-building helpers that iterate router.resources() and call url_for() without filtering; trying to reverse-generate the sub-app mount prefix; refactoring that accidentally captures the sub-app root instead of a specific route inside it.","solutions":["Call url_for() on a specific named route inside the sub-app, not on the sub-app root resource.","When iterating resources, skip those whose get_info() indicates a sub-app root (or skip resources that are instances of PrefixResource used for sub-apps).","Use named routes (name=...) and app.router.named_resources() to resolve URLs safely."],"exampleFix":"// before\nsub_root = app.router.add_subapp('/api', sub_app)\nurl = sub_root.url_for()  # RuntimeError\n// after\n# name a route inside the sub-app and reverse it\nsub_app.router.add_get('/users', users_handler, name='users')\nurl = sub_app.router['users'].url_for()","handlingStrategy":"type-guard","validationCode":"from aiohttp.web_urldispatcher import PrefixResource, AbstractResource\n\ndef url_for_safe(resource: AbstractResource, *args, **kwargs):\n    if isinstance(resource, PrefixResource):\n        raise RuntimeError(f'{resource!r} (sub-app root) does not support url_for()')\n    return resource.url_for(*args, **kwargs)","typeGuard":"from aiohttp.web_urldispatcher import PrefixResource\n\ndef supports_url_for(resource) -> bool:\n    return not isinstance(resource, PrefixResource)","tryCatchPattern":null,"preventionTips":["Iterate named resources rather than all resources when building URLs.","Filter out PrefixResource (sub-app roots) before calling url_for in generic helpers.","Name the routes inside sub-apps and reverse them via the sub-app's router."],"tags":["routing","sub-app","url-for"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}