aio-libs/aiohttp · error · RuntimeError
.url_for() is not supported by sub-application root
Error message
.url_for() is not supported by sub-application root
What it means
Raised as RuntimeError by PrefixedSubAppResource.url_for. Sub-application root resources are mounted under a prefix and do not have a single canonical URL to reverse, so calling url_for() on one is meaningless and explicitly rejected. Reverse URL lookups must target concrete named routes inside the sub-app (or the parent), not the sub-app mount point itself.
Source
Thrown at aiohttp/web_urldispatcher.py:729
super().__init__(prefix)
self._app = app
self._add_prefix_to_resources(prefix)
def add_prefix(self, prefix: str) -> None:
super().add_prefix(prefix)
self._add_prefix_to_resources(prefix)
def _add_prefix_to_resources(self, prefix: str) -> None:
router = self._app.router
for resource in router.resources():
# Since the canonical path of a resource is about
# to change, we need to unindex it and then reindex
router.unindex_resource(resource)
resource.add_prefix(prefix)
router.index_resource(resource)
def url_for(self, *args: str, **kwargs: str) -> URL:
raise RuntimeError(".url_for() is not supported by sub-application root")
def get_info(self) -> _InfoDict:
return {"app": self._app, "prefix": self._prefix}
async def resolve(self, request: Request) -> _Resolve:
match_info = await self._app.router.resolve(request)
match_info.add_app(self._app)
if isinstance(match_info.http_exception, HTTPMethodNotAllowed):
methods = match_info.http_exception.allowed_methods
else:
methods = set()
return match_info, methods
def __len__(self) -> int:
return len(self._app.router.routes())
def __iter__(self) -> Iterator[AbstractRoute]:
return iter(self._app.router.routes())View on GitHub (pinned to c0ef574e29)
Solutions
- Reverse a named concrete route inside the sub-application instead of the sub-app resource.
- When iterating resources, skip PrefixedSubAppResource / check isinstance before calling url_for.
- Give the target route a name and use app.router.named_resources()['name'].url_for(...).
- Build the sub-app URL manually by concatenating the prefix if you truly need the mount point.
Example fix
# before
url = sub_app_resource.url_for() # raises
# after
# name a route inside the sub-app, reverse that
sub_app.router.add_get('/items', handler, name='items')
url = sub_app.router.named_resources()['items'].url_for() Defensive patterns
Strategy: type-guard
Validate before calling
from aiohttp.web_urldispatcher import PrefixedSubAppResource, AbstractResource
def safe_url_for(resource, **kw):
if isinstance(resource, PrefixedSubAppResource):
raise RuntimeError(f"cannot url_for sub-app resource {resource!r}; reverse a named route inside it")
return resource.url_for(**kw) Type guard
from aiohttp.web_urldispatcher import PrefixedSubAppResource
def can_url_for(resource) -> bool:
return not isinstance(resource, PrefixedSubAppResource) Try / catch
try:
url = resource.url_for()
except RuntimeError as e:
if 'not supported by sub-application' in str(e):
url = None # skip sub-app roots in bulk reverse operations
else:
raise Prevention
- When iterating resources, skip PrefixedSubAppResource before url_for.
- Name concrete routes inside sub-apps and reverse those instead.
- Keep a registry of reversible route names rather than reversing raw resources.
When it happens
Trigger: Calling app.router.named_resources()['sub_app_name'].url_for(...) or otherwise obtaining the PrefixedSubAppResource for an add_sub_app mount and invoking url_for on it. Also triggered by code iterating resources and calling url_for generically.
Common situations: Generic resource-iteration code that calls url_for() on every resource without checking type; assuming sub-app mounts are reverse-able like named routes; migration from plain routes to sub-apps.
Related errors
- Cannot change apps stack after .freeze() call
- Expected one of the following apps {self._apps!r}, got {app!
- Added route will never be executed, method {route.method} is
- OPTIONS route was set already
- Domain must be str
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/dc5170ebea3bea22.json.
Report an issue: GitHub.