aio-libs/aiohttp · error · ValueError

is not allowed HTTP method

Error message

{method} is not allowed HTTP method

What it means

When registering a route, aiohttp uppercases the method and validates it against HTTP_METHOD_RE (RFC 7230 token characters: alphanumerics and a subset of symbols). A method that does not match — e.g. contains spaces, lowercase handled fine by upper(), but embedded slashes, colons, or empty strings — raises ValueError. This protects the router from registering routes that can never match a real HTTP request line.

Solutions

  1. Pass a single, valid HTTP method token as a string: 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', or a custom token matching [A-Za-z0-9!#$%&'*+-.^_`|~].
  2. If you have a comma-separated list, split and register each method individually.
  3. Strip whitespace and verify there are no newline/control characters before registering.

Example fix

// before
resource.add_route('GET, POST', handler)
// after
resource.add_route('GET', handler)
resource.add_route('POST', handler)
Defensive patterns

Strategy: validation

Validate before calling

import re
from aiohttp.web_urldispatcher import HTTP_METHOD_RE

def validate_method(method: str) -> str:
    method = method.upper()
    if not HTTP_METHOD_RE.match(method):
        raise ValueError(f'Invalid HTTP method: {method!r}')
    return method

Prevention

When it happens

Trigger: Calling resource.add_route() or app.router.add_route() / app.router.add_get() with a malformed method string: empty string, a string containing spaces or commas (e.g. 'GET, POST'), a method with invalid characters like 'GET/' or 'GET\n'. Also passing a method already containing a custom verb with disallowed punctuation.

Common situations: Typos; splitting a comma-separated method list instead of registering each separately; passing the full HTTP request line ('GET /path'); using a method name with a hyphen that includes an invalid symbol; test code that passes arbitrary strings.

Related errors


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

Appendix: source

Thrown at aiohttp/web_urldispatcher.py:166

class AbstractRoute(abc.ABC):
    def __init__(
        self,
        method: str,
        handler: Handler | type[AbstractView],
        *,
        expect_handler: _ExpectHandler | None = None,
        resource: AbstractResource | None = None,
    ) -> None:
        if expect_handler is None:
            expect_handler = _default_expect_handler

        assert inspect.iscoroutinefunction(expect_handler) or (
            sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler)  # type: ignore[deprecated]
        ), f"Coroutine is expected, got {expect_handler!r}"

        method = method.upper()
        if not HTTP_METHOD_RE.match(method):
            raise ValueError(f"{method} is not allowed HTTP method")

        if inspect.iscoroutinefunction(handler) or (
            sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler)  # type: ignore[deprecated]
        ):
            pass
        elif isinstance(handler, type) and issubclass(handler, AbstractView):
            pass
        else:
            raise TypeError(
                f"Only async functions are allowed as web-handlers, got {handler!r}"
            )

        self._method = method
        self._handler = handler
        self._expect_handler = expect_handler
        self._resource = resource

    @property

View on GitHub (pinned to d041d4d0fd)