aio-libs/aiohttp · error · ValueError
Incorrect route name
Error message
Incorrect route name {name!r}, python keywords cannot be used for route name What it means
register_resource() splits the route name on '.', ':', '-' (NAME_SPLIT_RE) and rejects the resource if any segment is a Python keyword (class, def, return, async, etc.). Route names are used by app.router.named_resources and by url_for(), and aiohttp wants each segment to be a valid Python identifier so generated code or attribute-style lookups stay legal. This runs after the frozen check but before the duplicate check.
Solutions
- Rename the route so no dot/dash/colon-separated segment is a Python keyword (e.g. 'klass', 'item-import').
- When generating names from data, sanitize against keyword.iskeyword() before passing to add_route.
- Avoid names that match the full keyword list (keyword.kwlist).
Example fix
// before
app.router.add_get('/class/{id}', handler, name='class')
// after
app.router.add_get('/class/{id}', handler, name='klass') Defensive patterns
Strategy: validation
Validate before calling
import keyword
def safe_route_name(name: str) -> str:
for part in re.split(r'[.:-]', name):
if keyword.iskeyword(part):
raise ValueError(f'route name segment {part!r} is a python keyword')
return name
name = safe_route_name(generated_name)
app.router.add_get('/x', h, name=name) Type guard
import keyword, re
def is_valid_route_name(name: str) -> bool:
return (
isinstance(name, str)
and all(
not keyword.iskeyword(p) and p.isidentifier()
for p in re.split(r'[.:-]', name)
)
) Try / catch
try:
app.router.add_get('/x', h, name=name)
except ValueError as e:
if 'keyword' in str(e):
name = name + '_route' # disambiguate and retry
app.router.add_get('/x', h, name=name)
else:
raise Prevention
- Avoid Python keywords as name segments; keep a project-wide allow-list.
- When generating names from data, filter out keyword.iskeyword matches.
- Namespace names with a prefix/suffix to avoid collisions with keywords.
When it happens
Trigger: Calling app.router.add_get('class', ...) or add_route('GET', '/x', h, name='class'); using a multi-segment name like 'api.return' or 'auth.class' (each segment is checked); programmatically generating names from user input that happens to be a keyword.
Common situations: Auto-generating route names from resource nouns that collide with keywords ('class', 'import', 'global', 'lambda'); REST naming conventions that produce segments like 'import' or 'return'.
Related errors
- Incorrect route name
- Domain not valid
- Duplicate , already handled by
- path should be started with / or be empty
- Scheme not supported
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/22b35b53d8e66f1c.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/web_urldispatcher.py:1053
return RoutesView(self._resources)
def named_resources(self) -> Mapping[str, AbstractResource]:
return MappingProxyType(self._named_resources)
def register_resource(self, resource: AbstractResource) -> None:
assert isinstance(
resource, AbstractResource
), f"Instance of AbstractResource class is required, got {resource!r}"
if self.frozen:
raise RuntimeError("Cannot register a resource into frozen router.")
name = resource.name
if name is not None:
parts = self.NAME_SPLIT_RE.split(name)
for part in parts:
if keyword.iskeyword(part):
raise ValueError(
f"Incorrect route name {name!r}, "
"python keywords cannot be used "
"for route name"
)
if not part.isidentifier():
raise ValueError(
f"Incorrect route name {name!r}, "
"the name should be a sequence of "
"python identifiers separated "
"by dash, dot or column"
)
if name in self._named_resources:
raise ValueError(
f"Duplicate {name!r}, "
f"already handled by {self._named_resources[name]!r}"
)
self._named_resources[name] = resource
self._resources.append(resource)View on GitHub (pinned to d041d4d0fd)