{"record":{"id":"f8c51b3d9efd572f","repo":"assafelovic/gpt-researcher","slug":"host-host-r-resolved-to-an-invalid-address-ip-s","errorCode":null,"errorMessage":"Host {host!r} resolved to an invalid address {ip_str!r}.","messagePattern":"Host (.+?) resolved to an invalid address (.+?)\\.","errorType":"validation","errorClass":"UnsafeURLError","httpStatus":null,"severity":"error","filePath":"gpt_researcher/utils/url_security.py","lineNumber":107,"sourceCode":"    if not host:\n        raise UnsafeURLError(\"URL must include a valid host.\")\n\n    if allow_private is None:\n        allow_private = _private_urls_allowed()\n    if allow_private:\n        return url\n\n    try:\n        addrinfo = socket.getaddrinfo(host, None)\n    except socket.gaierror as exc:\n        raise UnsafeURLError(f\"Could not resolve host {host!r}: {exc}\") from exc\n\n    for info in addrinfo:\n        ip_str = info[4][0]\n        try:\n            ip = ipaddress.ip_address(ip_str)\n        except ValueError as exc:\n            raise UnsafeURLError(\n                f\"Host {host!r} resolved to an invalid address {ip_str!r}.\"\n            ) from exc\n        if _is_disallowed_ip(ip):\n            raise UnsafeURLError(\n                f\"URL host {host!r} resolves to a non-public address ({ip_str}); \"\n                \"set ALLOW_PRIVATE_URLS=true to allow internal targets.\"\n            )\n\n    return url\n\n\ndef is_safe_url(url: str, *, allow_private: bool | None = None) -> bool:\n    \"\"\"Return ``True`` if ``url`` passes :func:`validate_url`, else ``False``.\"\"\"\n    try:\n        validate_url(url, allow_private=allow_private)\n        return True\n    except UnsafeURLError:\n        return False","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/assafelovic/gpt-researcher/blob/6f998577d547b1e54ec662dac63583aa11e3b84b/gpt_researcher/utils/url_security.py#L89-L125","documentation":"Raised when DNS returns an address string for the host that Python's ipaddress module cannot parse into an IP object. This is a defensive guard in validate_url's SSRF check loop; it almost never fires because getaddrinfo normally returns valid addresses.","triggerScenarios":"socket.getaddrinfo returns a sockaddr whose first element is not a parseable IP (e.g. unusual resolver output, a hostname embedded instead of an address, or a mocked getaddrinfo in tests returning garbage).","commonSituations":"Unit tests that patch socket.getaddrinfo with tuples like (None, None, None, '', ('not-an-ip', 0)); exotic resolvers or OS-level DNS interception returning non-standard results.","solutions":["If mocking getaddrinfo in tests, return realistic tuples: (socket.AF_INET, None, None, '', ('93.184.216.34', 0)).","Check the host with 'socket.getaddrinfo(host, None)' in a REPL to inspect what your resolver returns; fix local DNS/hosts-file entries.","Report upstream if it occurs without mocking, including resolver output and OS."],"exampleFix":"# before (test mock causes the error)\nmock_getaddrinfo.return_value = [(None, None, None, '', ('bogus', 0))]\n# after\nmock_getaddrinfo.return_value = [(socket.AF_INET, None, None, '', ('93.184.216.34', 0))]","handlingStrategy":"try-catch","validationCode":"import socket, ipaddress\n\ndef resolves_to_valid_ips(host: str) -> bool:\n    try:\n        return all(\n            (lambda s: (ipaddress.ip_address(s), True)[1])(i[4][0])\n            for i in socket.getaddrinfo(host, None)\n        )\n    except (socket.gaierror, ValueError):\n        return False","typeGuard":null,"tryCatchPattern":"from gpt_researcher.utils.url_security import UnsafeURLError\ntry:\n    validate_url(url)\nexcept UnsafeURLError as e:\n    if \"invalid address\" in str(e):\n        logger.error(\"resolver returned unparseable address for %s; check DNS/mock\", url)\n    raise","preventionTips":["When mocking getaddrinfo, return well-formed sockaddr tuples with real IP strings.","Investigate local DNS/hosts-file oddities if this appears outside tests."],"tags":["dns","ssrf-protection","python","testing"],"backgroundTag":"invalid-ip-address","analyzedSha":"6f998577d547b1e54ec662dac63583aa11e3b84b","analyzedAt":"2026-08-28T17:50:07.383Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}