Graphify-Labs/graphify · warning · ValueError

DNS resolution failed for '{hostname}': {exc}. Got: {url!r}

Error message

DNS resolution failed for '{hostname}': {exc}. Got: {url!r}

What it means

ValueError from validate_url when socket.getaddrinfo raises gaierror - the hostname does not resolve at all. Wrapped with `from exc` so the underlying resolver error (NXDOMAIN, timeout) stays in the chain. This is DNS failure rather than a policy block: the guard tries to check the IP but cannot get one.

Source

Thrown at graphify/security.py:139

        if hostname.lower() in _BLOCKED_HOSTS:
            raise ValueError(
                f"Blocked cloud metadata endpoint '{hostname}'. "
                f"Got: {url!r}"
            )

        # Resolve hostname and block private/reserved IP ranges
        try:
            infos = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
            for info in infos:
                addr = info[4][0]
                ip = ipaddress.ip_address(addr)
                if _ip_is_blocked(ip):
                    raise ValueError(
                        f"Blocked private/internal IP {addr} (resolved from '{hostname}'). "
                        f"Got: {url!r}"
                    )
        except socket.gaierror as exc:
            raise ValueError(
                f"DNS resolution failed for '{hostname}': {exc}. Got: {url!r}"
            ) from exc

    return url


# ---------------------------------------------------------------------------
# SSRF-guarded connections
#
# Instead of monkey-patching the process-global socket.getaddrinfo (a
# non-thread-safe TOCTOU hazard when multiple fetches run concurrently),
# we subclass the HTTP(S) connection so each connection resolves DNS exactly
# once, validates the resulting IP, and then connects to that exact IP. There
# is no second resolution, so a DNS-rebind attack cannot swap in a private
# address (e.g. 169.254.169.254) between validation and connection.
# ---------------------------------------------------------------------------

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Check the name resolves where graphify runs: `getent hosts <hostname>` or `python -c "import socket; print(socket.getaddrinfo('<hostname>', None))"`.
  2. Fix typos / use the canonical hostname.
  3. If it is an internal name, get on the right network/VPN or fix search-domain (resolv.conf search=) configuration.
  4. If DNS is flaky, retry - resolver timeouts masquerade as this error.

Example fix

# before
url = 'https://api.exmaple.com/v1'   # typo
fetch(validate_url(url))             # ValueError: DNS resolution failed for 'api.exmaple.com'

# after
url = 'https://api.example.com/v1'
fetch(validate_url(url))
Defensive patterns

Strategy: validation

Validate before calling

import socket
from urllib.parse import urlparse

host = urlparse(url).hostname or ""
try:
    socket.getaddrinfo(host, None)
except socket.gaierror:
    raise SystemExit(f"{host} does not resolve from this machine - fix DNS/VPN/name")

Type guard

def is_safe_url(url: str) -> bool:
    try:
        validate_url(url)
        return True
    except ValueError:
        return False

Try / catch

try:
    safe = validate_url(url)
except ValueError as exc:
    if "DNS resolution failed" in str(exc):
        return bad_request("hostname does not resolve")  # user-fixable, 4xx
    if "Blocked" in str(exc):
        return forbidden(str(exc))                        # policy, audit it
    raise

Prevention

When it happens

Trigger: validate_url(url) where the hostname fails DNS resolution from the machine running graphify (security.py:137-140): typo'd domains, split-horizon DNS where the name only exists internally, resolver outages, air-gapped CI, or .local mDNS names the resolver refuses.

Common situations: CI runners without VPN access fetching internal-only hostnames; typos like 'exmaple.com'; IPv6-only DNS quirks; systemd-resolved stub issues in containers; domains that exist publicly but not from restrictive resolvers.

Understand the failure class

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/8c842bf824efa51c. Report an issue: GitHub.