{"id":"ab88abf46eb943a4","repo":"encode/httpx","slug":"relative-urls-cannot-have-a-path-starting-with-ab88ab","errorCode":null,"errorMessage":"Relative URLs cannot have a path starting with ':'","messagePattern":"Relative URLs cannot have a path starting with ':'","errorType":"validation","errorClass":"InvalidURL","httpStatus":null,"severity":"error","filePath":"httpx/_urlparse.py","lineNumber":444,"sourceCode":"\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:\n\n        normalize_path(\"/path/./to/somewhere/..\") == \"/path/to\"\n    \"\"\"\n    # Fast return when no '.' characters in the path.\n    if \".\" not in path:\n        return path\n\n    components = path.split(\"/\")\n\n    # Fast return when no '.' or '..' components in the path.\n    if \".\" not in components and \"..\" not in components:","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_urlparse.py#L426-L462","documentation":"Raised by validate_path when a relative URL (no scheme, no authority) starts with ':'. RFC 3986 §4.2 forbids the first path segment of a relative-path reference from containing a colon, because ':' would be ambiguous with a scheme delimiter. httpx rejects a leading ':' outright.","triggerScenarios":"httpx.URL(':foo'), httpx.URL(path=':bar'), or constructing a relative reference where the path begins with a colon.","commonSituations":"Building a relative URL that accidentally begins with ':' (e.g. from a templated value); user input starting with ':'; mis-formed link extraction.","solutions":["Prefix the path with './' to disambiguate: httpx.URL('./:foo').","Supply a scheme so the URL is absolute.","Strip or reject leading colons in user-supplied relative paths.","Use urljoin against a base URL rather than constructing relative URLs by hand."],"exampleFix":"// before\nurl = httpx.URL(\":foo\")  # InvalidURL\n\n// after\nurl = httpx.URL(\"./:foo\")  # or provide a full URL","handlingStrategy":"validation","validationCode":"def disambiguate_relative(path: str) -> str:\n    if path.startswith(\":\"):\n        return \"./\" + path\n    return path\n\nurl = httpx.URL(disambiguate_relative(user_path))","typeGuard":"def relative_path_is_safe(path: str) -> bool:\n    return not path.startswith(\":\")","tryCatchPattern":"from httpx import InvalidURL\n\ntry:\n    url = httpx.URL(p)\nexcept InvalidURL as e:\n    if \"cannot have a path starting with ':'\" in str(e):\n        url = httpx.URL(\"./\" + p)\n    else:\n        raise","preventionTips":["Prefix ':'-leading relative paths with './'.","Supply a scheme whenever possible to avoid relative-URL edge cases.","Reject leading ':' in user-supplied relative paths."],"tags":["url","path","rfc3986","relative-url","validation"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}