{"id":"435d08526a962d73","repo":"encode/httpx","slug":"invalid-ipv4-address-host-r","errorCode":null,"errorMessage":"Invalid IPv4 address: {host!r}","messagePattern":"Invalid IPv4 address: (.+?)","errorType":"validation","errorClass":"InvalidURL","httpStatus":null,"severity":"error","filePath":"httpx/_urlparse.py","lineNumber":361,"sourceCode":"        parsed_query,\n        parsed_frag,\n    )\n\n\ndef encode_host(host: str) -> str:\n    if not host:\n        return \"\"\n\n    elif IPv4_STYLE_HOSTNAME.match(host):\n        # Validate IPv4 hostnames like #.#.#.#\n        #\n        # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2\n        #\n        # IPv4address = dec-octet \".\" dec-octet \".\" dec-octet \".\" dec-octet\n        try:\n            ipaddress.IPv4Address(host)\n        except ipaddress.AddressValueError:\n            raise InvalidURL(f\"Invalid IPv4 address: {host!r}\")\n        return host\n\n    elif IPv6_STYLE_HOSTNAME.match(host):\n        # Validate IPv6 hostnames like [...]\n        #\n        # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2\n        #\n        # \"A host identified by an Internet Protocol literal address, version 6\n        # [RFC3513] or later, is distinguished by enclosing the IP literal\n        # within square brackets (\"[\" and \"]\").  This is the only place where\n        # square bracket characters are allowed in the URI syntax.\"\n        try:\n            ipaddress.IPv6Address(host[1:-1])\n        except ipaddress.AddressValueError:\n            raise InvalidURL(f\"Invalid IPv6 address: {host!r}\")\n        return host[1:-1]\n\n    elif host.isascii():","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_urlparse.py#L343-L379","documentation":"Raised by encode_host when the host looks like an IPv4 dotted-quad (matches ^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$) but ipaddress.IPv4Address() rejects it (e.g. an octet > 255 or negative). Each octet must be a valid 0-255 decimal; leading zeros are also rejected by modern Python.","triggerScenarios":"httpx.URL('http://999.0.0.1/'), httpx.URL(host='10.0.0.256'), or constructing a URL with host='192.168.1.300'.","commonSituations":"Off-by-one IP generation; user-typed IP with a typo; arithmetic that produces an octet > 255; legacy code emitting leading-zero octets like '010.0.0.1'.","solutions":["Validate the IP with ipaddress.IPv4Address(host) before building the URL.","Clamp generated octets to 0-255 in any code that synthesizes IPs.","Strip whitespace/dots from user input before parsing.","If a hostname (not an IP) is intended, ensure it does not match the dotted-quad regex."],"exampleFix":"// before\nurl = httpx.URL(\"http://10.0.0.300/\")  # Invalid IPv4 address\n\n// after\nimport ipaddress\nhost = \"10.0.0.300\"\nipaddress.IPv4Address(host)  # raises early, predictable\nurl = httpx.URL(\"http://10.0.0.30/\")","handlingStrategy":"validation","validationCode":"import ipaddress\n\ndef safe_ipv4(host: str) -> str:\n    ipaddress.IPv4Address(host)  # raises AddressValueError early\n    return host\n\nurl = httpx.URL(host=safe_ipv4(user_host))","typeGuard":"import ipaddress\n\ndef is_valid_ipv4(host: str) -> bool:\n    try:\n        ipaddress.IPv4Address(host)\n        return True\n    except ipaddress.AddressValueError:\n        return False","tryCatchPattern":"from httpx import InvalidURL\n\ntry:\n    url = httpx.URL(f\"http://{host}/\")\nexcept InvalidURL as e:\n    if \"Invalid IPv4\" in str(e):\n        # fall back to DNS hostname or reject input\n        raise ValueError(f\"Bad IP from user: {host!r}\") from e\n    raise","preventionTips":["Always validate IPs with the ipaddress module before use.","Clamp generated octets to 0-255.","Avoid leading-zero octet notation."],"tags":["url","ipv4","validation","network"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}