aio-libs/aiohttp · error · RuntimeError
Added route will never be executed, method {route.method} is
Error message
Added route will never be executed, method {route.method} is already registered What it means
Raised as RuntimeError by Resource.add_route when a route for the same HTTP method (or ANY) is already registered on that resource. Because route resolution returns the first registered match, a duplicate would be silently unreachable, so aiohttp rejects it to surface the likely configuration mistake.
Source
Thrown at aiohttp/web_urldispatcher.py:323
raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect)
class Resource(AbstractResource):
def __init__(self, *, name: str | None = None) -> None:
super().__init__(name=name)
self._routes: dict[str, ResourceRoute] = {}
self._any_route: ResourceRoute | None = None
self._allowed_methods: set[str] = set()
def add_route(
self,
method: str,
handler: type[AbstractView] | Handler,
*,
expect_handler: _ExpectHandler | None = None,
) -> "ResourceRoute":
if route := self._routes.get(method, self._any_route):
raise RuntimeError(
"Added route will never be executed, "
f"method {route.method} is already "
"registered"
)
route_obj = ResourceRoute(method, handler, self, expect_handler=expect_handler)
self.register_route(route_obj)
return route_obj
def register_route(self, route: "ResourceRoute") -> None:
assert isinstance(
route, ResourceRoute
), f"Instance of Route class is required, got {route!r}"
if route.method == hdrs.METH_ANY:
self._any_route = route
self._allowed_methods.add(route.method)
self._routes[route.method] = route
View on GitHub (pinned to c0ef574e29)
Solutions
- Remove the duplicate registration — keep a single handler per method per resource.
- If you need different handlers, give them distinct paths or distinct methods.
- Guard against double-import by registering routes in a function called once, or use an idempotent setup.
- If you intended to override, first remove/replace the existing route rather than adding alongside.
Example fix
# before
resource.add_route('GET', h1)
resource.add_route('GET', h2) # raises
# after
resource.add_route('GET', h1)
resource.add_route('POST', h2) Defensive patterns
Strategy: validation
Validate before calling
def register_unique(resource, method, handler):
if method in resource._routes or (resource._any_route and method == '*'):
raise RuntimeError(f"method {method} already registered on {resource}")
return resource.add_route(method, handler) Try / catch
try:
resource.add_route(method, handler)
except RuntimeError as e:
if 'already registered' in str(e):
log.warning("skipping duplicate route for %s", method)
else:
raise Prevention
- Register each method/path pair exactly once.
- Make route registration idempotent by keying on (path, method).
- Audit blueprints/plugins for overlapping route definitions.
When it happens
Trigger: Calling resource.add_route('GET', handler1) then resource.add_route('GET', handler2) on the same Resource. Also when add_get is called twice on the same path/resource, or mixing add_route('GET') with an ANY route already present (the ANY route shadows it).
Common situations: Two blueprint/blueprint registrations applying to the same prefix; importing a routes module twice; copy-paste creating duplicate add_get calls; registering both a method-specific route and a '*' (ANY) route on the same resource where ANY was registered first.
Related errors
- {method} is not allowed HTTP method
- Cannot change apps stack after .freeze() call
- Invalid path '{path}'['{part}']
- Only async functions are allowed as web-handlers, got {handl
- Expected one of the following apps {self._apps!r}, got {app!
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/489014cb915a8f4c.json.
Report an issue: GitHub.