{"id":"815e262992b8b8d0","repo":"encode/httpx","slug":"invalid-url-component-key","errorCode":null,"errorMessage":"Invalid URL component '{key}'","messagePattern":"Invalid URL component '(.+?)'","errorType":"validation","errorClass":"InvalidURL","httpStatus":null,"severity":"error","filePath":"httpx/_urlparse.py","lineNumber":286,"sourceCode":"            if len(value) > MAX_URL_LENGTH:\n                raise InvalidURL(f\"URL component '{key}' too long\")\n\n            # If a component includes any ASCII control characters including \\t, \\r, \\n,\n            # then treat it as invalid.\n            if any(char.isascii() and not char.isprintable() for char in value):\n                char = next(\n                    char for char in value if char.isascii() and not char.isprintable()\n                )\n                idx = value.find(char)\n                error = (\n                    f\"Invalid non-printable ASCII character in URL {key} component, \"\n                    f\"{char!r} at position {idx}.\"\n                )\n                raise InvalidURL(error)\n\n            # Ensure that keyword arguments match as a valid regex.\n            if not COMPONENT_REGEX[key].fullmatch(value):\n                raise InvalidURL(f\"Invalid URL component '{key}'\")\n\n    # The URL_REGEX will always match, but may have empty components.\n    url_match = URL_REGEX.match(url)\n    assert url_match is not None\n    url_dict = url_match.groupdict()\n\n    # * 'scheme', 'authority', and 'path' may be empty strings.\n    # * 'query' may be 'None', indicating no trailing \"?\" portion.\n    #   Any string including the empty string, indicates a trailing \"?\".\n    # * 'fragment' may be 'None', indicating no trailing \"#\" portion.\n    #   Any string including the empty string, indicates a trailing \"#\".\n    scheme = kwargs.get(\"scheme\", url_dict[\"scheme\"]) or \"\"\n    authority = kwargs.get(\"authority\", url_dict[\"authority\"]) or \"\"\n    path = kwargs.get(\"path\", url_dict[\"path\"]) or \"\"\n    query = kwargs.get(\"query\", url_dict[\"query\"])\n    frag = kwargs.get(\"fragment\", url_dict[\"fragment\"])\n\n    # The AUTHORITY_REGEX will always match, but may have empty components.","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_urlparse.py#L268-L304","documentation":"Raised during the kwargs validation loop when a component value fails to fully match its COMPONENT_REGEX. Each component has its own grammar (e.g. path must match '[^?#]*', scheme must match '([a-zA-Z][a-zA-Z0-9+.-]*)?'); a mismatch means the supplied value cannot be a valid component at all.","triggerScenarios":"httpx.URL(scheme='123bad') (scheme must start with a letter); httpx.URL(path='/a?b') (path must not contain '?'); httpx.URL(fragment='a#b') (fragment must not contain '#' as a sub-token... actually fragment regex is '.*' so any char passes, but other components are stricter).","commonSituations":"Programmatically building components without sanitization; passing a path that already includes a querystring instead of using raw_path/query; user input that breaks the scheme grammar.","solutions":["Split mixed input into the correct components (use raw_path= to pass '/p?x=1' rather than path=).","Validate the component against its expected grammar before constructing the URL.","For scheme, ensure it starts with a letter and contains only [a-zA-Z0-9+.-].","Use httpx.URL('full-string') and let httpx parse, rather than hand-building components."],"exampleFix":"// before\nurl = httpx.URL(scheme=\"https\", host=\"api.example.com\", path=\"/items?page=1\")  # Invalid URL component 'path'\n\n// after\nurl = httpx.URL(scheme=\"https\", host=\"api.example.com\", raw_path=\"/items?page=1\")","handlingStrategy":"validation","validationCode":"import re\n\nCOMPONENT_REGEX = {\n    \"scheme\": re.compile(r\"([a-zA-Z][a-zA-Z0-9+.-]*)?\"),\n    \"path\": re.compile(r\"[^?#]*\"),\n    \"query\": re.compile(r\"[^#]*\"),\n    # ... etc\n}\n\ndef validate_component(key: str, value: str) -> str:\n    if not COMPONENT_REGEX[key].fullmatch(value):\n        raise ValueError(f\"Invalid URL component {key!r}\")\n    return value","typeGuard":"import re\n\ndef path_is_valid(path: str) -> bool:\n    return re.fullmatch(r\"[^?#]*\", path) is not None","tryCatchPattern":"from httpx import InvalidURL\n\ntry:\n    url = httpx.URL(scheme=\"https\", host=\"x\", raw_path=mixed)\nexcept InvalidURL as e:\n    if \"Invalid URL component\" in str(e):\n        # split raw_path into path+query yourself, or use full-string URL\n        url = httpx.URL(f\"https://x{mixed}\")\n    else:\n        raise","preventionTips":["Use raw_path= (not path=) when the value may include a '?'.","Validate scheme starts with a letter and uses only [a-zA-Z0-9+.-].","Where possible, pass a complete URL string instead of hand-built components."],"tags":["url","validation","config","parsing"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}