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
- Point HTTPS clients at the HTTPS port and HTTP clients at the HTTP port.
- Ensure the request line has the form 'METHOD SP REQUEST-TARGET SP HTTP-VERSION' (three tokens).
- If building raw requests, include all three tokens separated by single spaces.
- 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
- Match the client scheme (http/https) to the server port
- Always send a complete three-token request line
- Use an HTTP library rather than raw sockets
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
- Bad status line {line!r}
- Bad line ending, expected CRLF
- {path}
- Got more than {limit} bytes when reading: {line!r}.
- Duplicate '{name}' header found.
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/4b66f33e6c445998.json.
Report an issue: GitHub.