aio-libs/aiohttp · error · BadHttpMethod

Bad HTTP method in status line {line!r}

Error message

Bad HTTP method in status line {line!r}

What it means

Raised by HttpRequestParser.parse_message (aiohttp/http_parser.py:659) when the request line cannot be split into three tokens (method, request-target, version) via str.split(' ', maxsplit=2). A ValueError (too few parts) is caught and re-raised as BadHttpMethod(line). Special case: if the line starts with '\x16\x03' (a TLS record header), BadHttpMethod sets the message to 'Received HTTPS traffic on an HTTP port'.

Source

Thrown at aiohttp/http_parser.py:659

        """
        self._upgraded = val


class HttpRequestParser(HttpParser[RawRequestMessage]):
    """Read request status line.

    Exception .http_exceptions.BadStatusLine
    could be raised in case of any errors in status line.
    Returns RawRequestMessage.
    """

    def parse_message(self, lines: list[bytes]) -> RawRequestMessage:
        # request line
        line = lines[0].decode("utf-8", "surrogateescape")
        try:
            method, path, version = line.split(" ", maxsplit=2)
        except ValueError:
            raise BadHttpMethod(line) from None

        # method
        if not TOKENRE.fullmatch(method):
            raise BadHttpMethod(method)
        method = method.upper()

        # version
        match = VERSRE.fullmatch(version)
        if match is None:
            raise BadStatusLine(line)
        version_o = HttpVersion(int(match.group(1)), int(match.group(2)))

        if method == "CONNECT":
            # authority-form,
            # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3
            url = URL.build(authority=path, encoded=True)
        elif path.startswith("/"):
            # origin-form,

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Point HTTPS clients at the HTTPS port and HTTP clients at the HTTP port.
  2. Ensure the request line has the form 'METHOD SP REQUEST-TARGET SP HTTP-VERSION' (three tokens).
  3. If building raw requests, include all three tokens separated by single spaces.
  4. Use a real HTTP library that formats the request line correctly.

Example fix

# before - TLS traffic to the plaintext port
client = ssl.wrap_socket(sock)   # then connect to host:80
# after - match scheme to port
# http://host:80/  OR  https://host:443/
# raw-client fix:
sock.send(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
Defensive patterns

Strategy: try-catch

Try / catch

from aiohttp import http_exceptions
try:
    await request.read()
except http_exceptions.BadStatusLine as e:
    line = getattr(e, 'line', '')
    if line.startswith('\x16\x03'):
        log.warning('HTTPS traffic on HTTP port from %s', request.remote)
    return web.Response(status=400)

Prevention

When it happens

Trigger: A request line with fewer than two spaces, e.g. 'GET\r\n' (method only), 'GET /index\r\n' (no version), an empty line, or pure garbage. The single most common real-world trigger is an HTTPS ClientHello ('\x16\x03...') arriving on a plaintext HTTP port.

Common situations: HTTPS client pointed at an HTTP port (or vice versa), port scanners, raw socket/telnet tests, or a client that forgot the HTTP version token when hand-building the request line.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/4b66f33e6c445998.json. Report an issue: GitHub.