{"id":"5013c9d9d28a644f","repo":"encode/httpx","slug":"invalid-port-port-r","errorCode":null,"errorMessage":"Invalid port: {port!r}","messagePattern":"Invalid port: (.+?)","errorType":"validation","errorClass":"InvalidURL","httpStatus":null,"severity":"error","filePath":"httpx/_urlparse.py","lineNumber":411,"sourceCode":"\n\ndef normalize_port(port: str | int | None, scheme: str) -> int | None:\n    # From https://tools.ietf.org/html/rfc3986#section-3.2.3\n    #\n    # \"A scheme may define a default port.  For example, the \"http\" scheme\n    # defines a default port of \"80\", corresponding to its reserved TCP\n    # port number.  The type of port designated by the port number (e.g.,\n    # TCP, UDP, SCTP) is defined by the URI scheme.  URI producers and\n    # normalizers should omit the port component and its \":\" delimiter if\n    # port is empty or if its value would be the same as that of the\n    # scheme's default.\"\n    if port is None or port == \"\":\n        return None\n\n    try:\n        port_as_int = int(port)\n    except ValueError:\n        raise InvalidURL(f\"Invalid port: {port!r}\")\n\n    # See https://url.spec.whatwg.org/#url-miscellaneous\n    default_port = {\"ftp\": 21, \"http\": 80, \"https\": 443, \"ws\": 80, \"wss\": 443}.get(\n        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:","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_urlparse.py#L393-L429","documentation":"Raised by normalize_port when the port string cannot be converted with int(port). Ports must be decimal integers; non-numeric strings (or floats-as-strings) are rejected as InvalidURL. Note a numeric-but-out-of-range port is NOT caught here (that surfaces from the OS at connect time).","triggerScenarios":"httpx.URL('http://host:abc/'), httpx.URL(host='h', port='8080.0'), or passing port as a stringified float.","commonSituations":"Reading the port from a config file as a string with a trailing newline or unit ('8080\\n', '8080/tcp'); passing a float by mistake; user input 'https'.","solutions":["Coerce the port to int explicitly before passing: port = int(port_str.strip()).","Validate the string with .isdecimal() and bounds 0 <= port <= 65535.","Strip whitespace/newlines from config-derived port strings.","Pass port as an int (the kwargs API accepts int) rather than a string."],"exampleFix":"// before\nport_from_config = \"8080\\n\"\nurl = httpx.URL(\"http://example.com\", port=port_from_config)  # Invalid port\n\n// after\nport = int(port_from_config.strip())\nurl = httpx.URL(\"http://example.com\", port=port)","handlingStrategy":"validation","validationCode":"def safe_port(port) -> int:\n    if isinstance(port, str):\n        port = port.strip()\n    p = int(port)  # ValueError surfaces here with a clean traceback\n    if not (0 <= p <= 65535):\n        raise ValueError(f\"Port out of range: {p}\")\n    return p\n\nurl = httpx.URL(\"http://example.com\", port=safe_port(port_cfg))","typeGuard":"def is_valid_port(value) -> bool:\n    try:\n        return 0 <= int(str(value).strip()) <= 65535\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"from httpx import InvalidURL\n\ntry:\n    url = httpx.URL(\"http://h\", port=raw_port)\nexcept InvalidURL as e:\n    if \"Invalid port\" in str(e):\n        raise ValueError(f\"Bad port from config: {raw_port!r}\") from e\n    raise","preventionTips":["Coerce port to int at config-load time, not at URL build time.","Strip whitespace/newlines from env-var-derived port strings.","Validate the 0-65535 range explicitly."],"tags":["url","port","validation","config"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}