{"record":{"id":"74c5144abf08e4d0","repo":"aio-libs/aiohttp","slug":"path","errorCode":null,"errorMessage":"{path}","messagePattern":"\\{path\\}","errorType":"exception","errorClass":"InvalidURLError","httpStatus":400,"severity":"error","filePath":"aiohttp/http_parser.py","lineNumber":704,"sourceCode":"            # NOTE: HTTP Request-Line input producing different\n            # NOTE: `yarl.URL()` objects\n            url = URL.build(\n                path=path_part,\n                query_string=qs_part,\n                fragment=url_fragment,\n                encoded=True,\n            )\n        elif path == \"*\" and method == \"OPTIONS\":\n            # asterisk-form,\n            url = URL(path, encoded=True)\n        else:\n            # absolute-form for proxy maybe,\n            # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2\n            url = URL(path, encoded=True)\n            if not url.absolute:\n                # authority-form is only allowed with CONNECT\n                # https://www.rfc-editor.org/info/rfc9112/#section-3.2.3-1\n                raise InvalidURLError(\n                    path.encode(errors=\"surrogateescape\").decode(\"latin1\")\n                )\n\n        # read headers\n        (\n            headers,\n            raw_headers,\n            close,\n            compression,\n            upgrade,\n            chunked,\n        ) = self.parse_headers(lines[1:])\n\n        if version_o == HttpVersion11 and hdrs.HOST not in headers:\n            raise BadHttpMessage(\"Missing 'Host' header in request.\")\n\n        if close is None:  # then the headers weren't set in the request\n            if version_o <= HttpVersion10:  # HTTP 1.0 must asks to not close","sourceCodeStart":686,"sourceCodeEnd":722,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_parser.py#L686-L722","documentation":"Raised as InvalidURLError (a BadHttpMessage subclass, HTTP 400) when the request-line path is not in origin-form ('/...'), asterisk-form ('*' with OPTIONS), or authority-form (only legal with CONNECT), and is not an absolute URI. Per RFC 9112 §3.2.3, the authority-form (host:port) is allowed ONLY with the CONNECT method. Any other method using authority-form, or a malformed non-absolute path, trips this guard.","triggerScenarios":"A client sends a request like 'GET example.com:443 HTTP/1.1' (authority-form with a non-CONNECT method), or 'GET foo HTTP/1.1' where 'foo' is neither a path starting with '/', nor '*', nor a valid absolute URL. Constructed by HttpRequestParser.parse_message when URL(path, encoded=True).absolute is False and the method is not CONNECT.","commonSituations":"Misconfigured HTTP client sending proxy-style requests (absolute URI or authority) to a non-proxy server; a proxy or load balancer forwarding the wrong request-target form; a malformed test harness (e.g. raw socket test) sending an invalid request line; curl used with '--resolve' or proxy options against an origin server.","solutions":["Send the request in origin-form (path beginning with '/') and put the host in the Host header, e.g. 'GET /path HTTP/1.1' with 'Host: example.com'.","If you need authority-form, use the CONNECT method (it is the only method allowed to use it).","If this is a proxy server, ensure the request-target is an absolute URI (http(s)://host/path) so url.absolute is True.","For raw-socket tests, validate the request-line against RFC 9112 §3.2 before sending."],"exampleFix":"// before (wrong target form)\r\nGET example.com:443 HTTP/1.1\\r\\n\\r\\n\r\n\r\n// after (origin-form + Host header)\r\nGET / HTTP/1.1\\r\\nHost: example.com\\r\\n\\r\\n\r\n\r\n// CONNECT is the only method allowed in authority-form\r\nCONNECT example.com:443 HTTP/1.1\\r\\nHost: example.com\\r\\n\\r\\n","handlingStrategy":"validation","validationCode":"import re\nfrom yarl import URL\n\ndef valid_request_target(method: str, path: str) -> bool:\n    # origin-form\n    if path.startswith('/'):\n        return True\n    # asterisk-form\n    if path == '*' and method.upper() == 'OPTIONS':\n        return True\n    # authority-form only with CONNECT\n    if method.upper() == 'CONNECT':\n        return bool(re.fullmatch(r'[A-Za-z0-9.\\-]+:\\d+', path))\n    # absolute-form (proxy)\n    try:\n        return URL(path, encoded=True).absolute\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"from aiohttp.http_exceptions import InvalidURLError, BadHttpMessage\n\ntry:\n    msg, payload, _ = parser.feed_data(raw)\nexcept InvalidURLError as e:\n    # 400 Bad Request to the peer; log the malformed target\n    respond_400(f'Invalid request target: {e.args[0] if e.args else \"\"}')\nexcept BadHttpMessage:\n    respond_400('Malformed request')","preventionTips":["Always send requests in origin-form ('/path') with a Host header unless using CONNECT.","Reserve authority-form strictly for CONNECT.","If acting as a proxy, accept and forward absolute-form URIs only.","Validate request-targets in test harnesses against RFC 9112 §3.2."],"tags":["http-parser","request-line","rfc-9112","invalid-url"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}