BerriAI/litellm · error · SSRFError

DNS resolution failed for '{hostname}': {e}

Error message

DNS resolution failed for '{hostname}': {e}

What it means

Raised by litellm's SSRF validator when socket.getaddrinfo fails with socket.gaierror while resolving the URL's hostname — i.e. DNS resolution itself failed (NXDOMAIN, resolver unreachable, temporary failure). The original gaierror text is embedded in the message. This is the network-level DNS error surfacing through the SSRF check, before any IP blocklist evaluation happens.

Source

Thrown at litellm/litellm_core_utils/url_utils.py:282

    if parsed.scheme not in _ALLOWED_SCHEMES:
        raise SSRFError(f"URL scheme '{parsed.scheme}' is not allowed")

    hostname: Final = parsed.hostname
    if not hostname:
        raise SSRFError("URL has no hostname")

    port: Final = parsed.port
    default_port: Final = _default_port_for_scheme(parsed.scheme)
    effective_port: Final = port if port is not None else default_port
    host_header: Final = _format_host_header(hostname, effective_port, default_port)

    is_allowlisted: Final = _is_host_allowlisted(hostname, effective_port)

    # Resolve hostname and validate ALL addresses
    try:
        addrinfo: Final = socket.getaddrinfo(hostname, effective_port, proto=socket.IPPROTO_TCP)
    except socket.gaierror as e:
        raise SSRFError(f"DNS resolution failed for '{hostname}': {e}")

    if not addrinfo:
        raise SSRFError(f"No addresses found for '{hostname}'")

    if not is_allowlisted:
        for family, type_, proto, canonname, sockaddr in addrinfo:
            resolved_ip = _sockaddr_host(sockaddr)
            if _is_blocked_ip(resolved_ip):
                raise SSRFError(
                    f"URL targets a blocked address ({resolved_ip}). "
                    "If this is a legitimate internal service, add the host "
                    "to `user_url_allowed_hosts` in general_settings."
                )

    # For HTTPS with SSL verification enabled, TLS certificate validation
    # binds the connection to the hostname — DNS rebinding can't redirect
    # to a different server because the cert wouldn't match.
    # When SSL verification is disabled, this defense doesn't apply, so

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Verify DNS from the same environment the proxy runs in: python -c "import socket; print(socket.getaddrinfo('HOST', 443, proto=socket.IPPROTO_TCP))".
  2. Fix the hostname typo or switch to an IP/FQDN that resolves.
  3. If internal DNS is required, fix resolv.conf/dnsPolicy/CoreDNS so the litellm process can resolve the host.
  4. If the host legitimately has no public DNS, add it to user_url_allowed_hosts only after confirming the IPs are safe — note the allowlist skips IP checks, so use it deliberately.

Example fix

# before
safe_get(client, "https://api.mycompany-int.example.com/fetch")  # NXDOMAIN

# after: verify DNS first, then use the resolvable internal name
import socket
assert socket.getaddrinfo("api.mycompany.internal", 443, proto=socket.IPPROTO_TCP)
safe_get(client, "https://api.mycompany.internal/fetch")
Defensive patterns

Strategy: try-catch

Validate before calling

import socket

def resolves(hostname: str) -> bool:
    try:
        socket.getaddrinfo(hostname, 443, proto=socket.IPPROTO_TCP)
        return True
    except socket.gaierror:
        return False

Try / catch

from litellm.litellm_core_utils.url_utils import SSRFError

try:
    resp = safe_get(client, url)
except SSRFError as e:
    if "DNS resolution failed" in str(e):
        return bad_request("hostname does not resolve from this environment")
    raise

Prevention

When it happens

Trigger: validate_url('https://nonexistent-host.example.com/...') where the hostname does not resolve; DNS server down or unreachable in the container/pod; a hostname that only resolves on an internal DNS that the litellm process cannot reach; IPv6-only hostname with no AAAA record and broken resolver behavior.

Common situations: Typos in api_base hostnames; Kubernetes pods with misconfigured dnsPolicy; corporate DNS not available from the deployment environment; /etc/resolv.conf misconfiguration; hostnames that resolve in a browser (via search-domain fallback) but not via getaddrinfo.

Understand the failure class

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/d44870ca28fa678b. Report an issue: GitHub.