{"record":{"id":"a71b654e08536454","repo":"aio-libs/aiohttp","slug":"bad-status-line-line-r","errorCode":null,"errorMessage":"Bad status line {line!r}","messagePattern":"Bad status line (.+?)","errorType":"exception","errorClass":"BadStatusLine","httpStatus":400,"severity":"error","filePath":"aiohttp/http_parser.py","lineNumber":671,"sourceCode":"    \"\"\"\n\n    def parse_message(self, lines: list[bytes]) -> RawRequestMessage:\n        # request line\n        line = lines[0].decode(\"utf-8\", \"surrogateescape\")\n        try:\n            method, path, version = line.split(\" \", maxsplit=2)\n        except ValueError:\n            raise BadHttpMethod(line) from None\n\n        # method\n        if not TOKENRE.fullmatch(method):\n            raise BadHttpMethod(method)\n        method = method.upper()\n\n        # version\n        match = VERSRE.fullmatch(version)\n        if match is None:\n            raise BadStatusLine(line)\n        version_o = HttpVersion(int(match.group(1)), int(match.group(2)))\n\n        if method == \"CONNECT\":\n            # authority-form,\n            # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3\n            url = URL.build(authority=path, encoded=True)\n        elif path.startswith(\"/\"):\n            # origin-form,\n            # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1\n            path_part, _hash_separator, url_fragment = path.partition(\"#\")\n            path_part, _question_mark_separator, qs_part = path_part.partition(\"?\")\n\n            # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based\n            # NOTE: parser does, otherwise it results into the same\n            # NOTE: HTTP Request-Line input producing different\n            # NOTE: `yarl.URL()` objects\n            url = URL.build(\n                path=path_part,","sourceCodeStart":653,"sourceCodeEnd":689,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_parser.py#L653-L689","documentation":"Raised when the protocol version token in the request line does not match VERSRE HTTP/(\\d)\\.(\\d). The request line must terminate with a valid 'HTTP/x.y' token (e.g. HTTP/1.0, HTTP/1.1, HTTP/2.0).","triggerScenarios":"A version that is missing or malformed: 'GET / HTTP1.1', 'GET / 1.1', 'GET / HTTP/1', 'GET / FTP/1.0', or 'GET /' with no version.","commonSituations":"Hand-crafted requests via raw sockets or netcat, custom clients with wrong version formatting, fuzzing, proxies injecting junk into the request line.","solutions":["Send 'HTTP/1.0' or 'HTTP/1.1' (or 'HTTP/2.0') exactly as the version token.","Use a real HTTP client library instead of raw sockets.","Audit any code that builds request lines by hand."],"exampleFix":"# before\nsock.send(b'GET / HTTP1.1\\r\\n\\r\\n')\n\n# after\nsock.send(b'GET / HTTP/1.1\\r\\n\\r\\n')","handlingStrategy":"validation","validationCode":"import re\n_VERS = re.compile(r'HTTP/(\\d)\\.(\\d)', re.ASCII)\ndef format_request_line(method: str, path: str) -> str:\n    if not _VERS.fullmatch('HTTP/1.1'):\n        raise ValueError\n    return f'{method} {path} HTTP/1.1'","typeGuard":"import re\n_VERS = re.compile(r'HTTP/(\\d)\\.(\\d)', re.ASCII)\ndef is_valid_version(tok: str) -> bool:\n    return bool(_VERS.fullmatch(tok))","tryCatchPattern":"from aiohttp.http_exceptions import BadStatusLine, BadHttpMessage\ntry:\n    ...parse...\nexcept BadStatusLine as e:\n    # e.line holds the offending request line; drop the peer\n    ...","preventionTips":["Always use the canonical 'HTTP/1.1' version token in hand-crafted requests.","Avoid building request lines by concatenating untrusted input."],"tags":["http","parser","request-line","version","validation"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}