{"id":"f2aa31ed9a2cc2cf","repo":"encode/httpx","slug":"for-absolute-urls-path-must-be-empty-or-begin-wit","errorCode":null,"errorMessage":"For absolute URLs, path must be empty or begin with '/'","messagePattern":"For absolute URLs, path must be empty or begin with '/'","errorType":"validation","errorClass":"InvalidURL","httpStatus":null,"severity":"error","filePath":"httpx/_urlparse.py","lineNumber":433,"sourceCode":"        scheme\n    )\n    if port_as_int == default_port:\n        return None\n    return port_as_int\n\n\ndef validate_path(path: str, has_scheme: bool, has_authority: bool) -> None:\n    \"\"\"\n    Path validation rules that depend on if the URL contains\n    a scheme or authority component.\n\n    See https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3\n    \"\"\"\n    if has_authority:\n        # If a URI contains an authority component, then the path component\n        # must either be empty or begin with a slash (\"/\") character.\"\n        if path and not path.startswith(\"/\"):\n            raise InvalidURL(\"For absolute URLs, path must be empty or begin with '/'\")\n\n    if not has_scheme and not has_authority:\n        # If a URI does not contain an authority component, then the path cannot begin\n        # with two slash characters (\"//\").\n        if path.startswith(\"//\"):\n            raise InvalidURL(\"Relative URLs cannot have a path starting with '//'\")\n\n        # In addition, a URI reference (Section 4.1) may be a relative-path reference,\n        # in which case the first path segment cannot contain a colon (\":\") character.\n        if path.startswith(\":\"):\n            raise InvalidURL(\"Relative URLs cannot have a path starting with ':'\")\n\n\ndef normalize_path(path: str) -> str:\n    \"\"\"\n    Drop \".\" and \"..\" segments from a URL path.\n\n    For example:","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_urlparse.py#L415-L451","documentation":"Raised by validate_path when the URL has an authority (host) but the path is non-empty and does not start with '/'. Per RFC 3986 §3.3, an absolute URI with an authority component must have a path that is empty or begins with '/'. A path like 'foo' after a host is ambiguous and rejected.","triggerScenarios":"httpx.URL('https://example.comfoo') (missing slash), or building a URL with host='example.com' and path='foo' (no leading slash).","commonSituations":"String-concatenating a host and a path without a separating '/'; user-supplied path that omits the leading slash; copy-paste dropping the slash.","solutions":["Ensure path begins with '/' when an authority is present: path = '/' + path if path and not path.startswith('/') else path.","Use httpx.URL(...) and then url.copy_with(path=normalized) rather than concatenation.","Validate with: if host and path and not path.startswith('/'): raise.","Prefer urljoin('https://example.com/', 'foo') which inserts the slash."],"exampleFix":"// before\nurl = httpx.URL(scheme=\"https\", host=\"example.com\", path=\"items/1\")  # InvalidURL\n\n// after\nurl = httpx.URL(scheme=\"https\", host=\"example.com\", path=\"/items/1\")","handlingStrategy":"validation","validationCode":"def join_path(host: str, path: str) -> str:\n    if path and not path.startswith(\"/\"):\n        path = \"/\" + path\n    return path\n\nurl = httpx.URL(scheme=\"https\", host=host, path=join_path(host, user_path))","typeGuard":"def path_ok_for_absolute(path: str) -> bool:\n    return not path or path.startswith(\"/\")","tryCatchPattern":"from httpx import InvalidURL\n\ntry:\n    url = httpx.URL(scheme=\"https\", host=\"x\", path=p)\nexcept InvalidURL as e:\n    if \"must be empty or begin with '/'\" in str(e):\n        url = httpx.URL(scheme=\"https\", host=\"x\", path=\"/\" + p)\n    else:\n        raise","preventionTips":["Always prefix user-supplied paths with '/' when joining to a host.","Prefer urllib.parse.urljoin over string concatenation.","Assert path invariants in URL-builder unit tests."],"tags":["url","path","rfc3986","validation"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}