aio-libs/aiohttp · error · RuntimeError

Added route will never be executed, method

Error message

Added route will never be executed, method {route.method} is already registered

What it means

Resource.add_route refuses to register a second route for the same HTTP method (or for the catch-all ANY method) on the same Resource, because the second handler would be unreachable — the first registered route always wins. The check looks up self._routes.get(method) and also checks self._any_route. Raising early prevents silent shadowing where a developer believes two handlers both run but only one ever does.

Solutions

  1. Remove or rename the duplicate registration so each (resource, method) pair has exactly one handler.
  2. If you need different handlers, give the paths distinct templates or use distinct resource names.
  3. Search the route table for the conflicting method/path before re-registering.

Example fix

// before
resource.add_route('GET', get_items)
resource.add_route('GET', get_items_v2)  # RuntimeError
// after
resource.add_route('GET', get_items_v2)  # only register the one you want
Defensive patterns

Strategy: validation

Validate before calling

def safe_add_route(resource, method, handler):
    if method in getattr(resource, '_routes', {}):
        raise RuntimeError(f'{method} already registered on this resource')
    return resource.add_route(method, handler)

Prevention

When it happens

Trigger: Calling resource.add_route('GET', h1) then resource.add_route('GET', h2) on the same Resource; or registering ANY handler (via add_route with method '*') and then a specific method. Also happens via app.router.add_get twice on the same path when they resolve to the same underlying Resource.

Common situations: Copy-pasting route registration and forgetting the first one exists; refactoring that moves routes without removing the originals; conditional registration that runs twice; building routes in a loop where a path collides.

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/489014cb915a8f4c. Report an issue: GitHub.

Appendix: 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 d041d4d0fd)