{"record":{"id":"d44870ca28fa678b","repo":"BerriAI/litellm","slug":"dns-resolution-failed-for-hostname-e","errorCode":null,"errorMessage":"DNS resolution failed for '{hostname}': {e}","messagePattern":"DNS resolution failed for '(.+?)': (.+?)","errorType":"exception","errorClass":"SSRFError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/url_utils.py","lineNumber":282,"sourceCode":"    if parsed.scheme not in _ALLOWED_SCHEMES:\n        raise SSRFError(f\"URL scheme '{parsed.scheme}' is not allowed\")\n\n    hostname: Final = parsed.hostname\n    if not hostname:\n        raise SSRFError(\"URL has no hostname\")\n\n    port: Final = parsed.port\n    default_port: Final = _default_port_for_scheme(parsed.scheme)\n    effective_port: Final = port if port is not None else default_port\n    host_header: Final = _format_host_header(hostname, effective_port, default_port)\n\n    is_allowlisted: Final = _is_host_allowlisted(hostname, effective_port)\n\n    # Resolve hostname and validate ALL addresses\n    try:\n        addrinfo: Final = socket.getaddrinfo(hostname, effective_port, proto=socket.IPPROTO_TCP)\n    except socket.gaierror as e:\n        raise SSRFError(f\"DNS resolution failed for '{hostname}': {e}\")\n\n    if not addrinfo:\n        raise SSRFError(f\"No addresses found for '{hostname}'\")\n\n    if not is_allowlisted:\n        for family, type_, proto, canonname, sockaddr in addrinfo:\n            resolved_ip = _sockaddr_host(sockaddr)\n            if _is_blocked_ip(resolved_ip):\n                raise SSRFError(\n                    f\"URL targets a blocked address ({resolved_ip}). \"\n                    \"If this is a legitimate internal service, add the host \"\n                    \"to `user_url_allowed_hosts` in general_settings.\"\n                )\n\n    # For HTTPS with SSL verification enabled, TLS certificate validation\n    # binds the connection to the hostname — DNS rebinding can't redirect\n    # to a different server because the cert wouldn't match.\n    # When SSL verification is disabled, this defense doesn't apply, so","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/url_utils.py#L264-L300","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify DNS from the same environment the proxy runs in: python -c \"import socket; print(socket.getaddrinfo('HOST', 443, proto=socket.IPPROTO_TCP))\".","Fix the hostname typo or switch to an IP/FQDN that resolves.","If internal DNS is required, fix resolv.conf/dnsPolicy/CoreDNS so the litellm process can resolve the host.","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."],"exampleFix":"# before\nsafe_get(client, \"https://api.mycompany-int.example.com/fetch\")  # NXDOMAIN\n\n# after: verify DNS first, then use the resolvable internal name\nimport socket\nassert socket.getaddrinfo(\"api.mycompany.internal\", 443, proto=socket.IPPROTO_TCP)\nsafe_get(client, \"https://api.mycompany.internal/fetch\")","handlingStrategy":"try-catch","validationCode":"import socket\n\ndef resolves(hostname: str) -> bool:\n    try:\n        socket.getaddrinfo(hostname, 443, proto=socket.IPPROTO_TCP)\n        return True\n    except socket.gaierror:\n        return False","typeGuard":null,"tryCatchPattern":"from litellm.litellm_core_utils.url_utils import SSRFError\n\ntry:\n    resp = safe_get(client, url)\nexcept SSRFError as e:\n    if \"DNS resolution failed\" in str(e):\n        return bad_request(\"hostname does not resolve from this environment\")\n    raise","preventionTips":["Pre-flight resolve hostnames with socket.getaddrinfo from the same container/pod.","Verify DNS config (resolv.conf, dnsPolicy) in deployments needing internal names.","Distinguish DNS failures from blocklist hits in error handling — remediation differs."],"tags":["ssrf","dns","network","gaierror"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}