assafelovic/gpt-researcher · error · UnsafeURLError
Host {host!r} resolved to an invalid address {ip_str!r}.
Error message
Host {host!r} resolved to an invalid address {ip_str!r}. What it means
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.
Source
Thrown at gpt_researcher/utils/url_security.py:107
if not host:
raise UnsafeURLError("URL must include a valid host.")
if allow_private is None:
allow_private = _private_urls_allowed()
if allow_private:
return url
try:
addrinfo = socket.getaddrinfo(host, None)
except socket.gaierror as exc:
raise UnsafeURLError(f"Could not resolve host {host!r}: {exc}") from exc
for info in addrinfo:
ip_str = info[4][0]
try:
ip = ipaddress.ip_address(ip_str)
except ValueError as exc:
raise UnsafeURLError(
f"Host {host!r} resolved to an invalid address {ip_str!r}."
) from exc
if _is_disallowed_ip(ip):
raise UnsafeURLError(
f"URL host {host!r} resolves to a non-public address ({ip_str}); "
"set ALLOW_PRIVATE_URLS=true to allow internal targets."
)
return url
def is_safe_url(url: str, *, allow_private: bool | None = None) -> bool:
"""Return ``True`` if ``url`` passes :func:`validate_url`, else ``False``."""
try:
validate_url(url, allow_private=allow_private)
return True
except UnsafeURLError:
return FalseView on GitHub (pinned to 6f998577d5)
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.
Example fix
# before (test mock causes the error)
mock_getaddrinfo.return_value = [(None, None, None, '', ('bogus', 0))]
# after
mock_getaddrinfo.return_value = [(socket.AF_INET, None, None, '', ('93.184.216.34', 0))] Defensive patterns
Strategy: try-catch
Validate before calling
import socket, ipaddress
def resolves_to_valid_ips(host: str) -> bool:
try:
return all(
(lambda s: (ipaddress.ip_address(s), True)[1])(i[4][0])
for i in socket.getaddrinfo(host, None)
)
except (socket.gaierror, ValueError):
return False Try / catch
from gpt_researcher.utils.url_security import UnsafeURLError
try:
validate_url(url)
except UnsafeURLError as e:
if "invalid address" in str(e):
logger.error("resolver returned unparseable address for %s; check DNS/mock", url)
raise Prevention
- When mocking getaddrinfo, return well-formed sockaddr tuples with real IP strings.
- Investigate local DNS/hosts-file oddities if this appears outside tests.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Could not resolve host {host!r}: {exc}
- URL must include a valid host.
- URL host {host!r} resolves to a non-public address ({ip_str}
- Cost must be an integer or float
- Embedding provider not found.
AI-assisted analysis of assafelovic/gpt-researcher@6f998577d5 (2026-08-28).
Data as JSON: /api/errors/f8c51b3d9efd572f.
Report an issue: GitHub.