{"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/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/litellm_core_utils/url_utils.py#L264-L300","documentation":"SSRFError raised when socket.getaddrinfo fails for the URL's hostname during SSRF validation; the underlying socket.gaierror is embedded in the message. This is an environmental DNS failure (name does not exist, resolver unreachable), not a policy decision — it happens before any address can be checked against the block list.","triggerScenarios":"Fetching a user URL whose host is typo'd or nonexistent (NXDOMAIN), a resolver outage in the container, an air-gapped or restricted network, or an internal hostname (.local, split-horizon name) the proxy's resolver cannot resolve.","commonSituations":"Self-hosted proxy deployments where the proxy pod uses different DNS than dev machines; expired domains in stored URLs; Kubernetes setups missing the internal DNS suffix.","solutions":["From the proxy host, verify resolution: getent hosts <hostname> or dig <hostname>.","Fix the hostname typo or point the URL at a resolvable name.","For internal names, ensure the proxy's resolver can find them (DNS entry, search suffix, or hosts file).","Catch SSRFError and surface a 'could not resolve host' 4xx/502 to the caller instead of a 500."],"exampleFix":"# before\nresp = safe_get(client, user_url)  # unhandled SSRFError -> 500\n\n# after\ntry:\n    resp = safe_get(client, user_url)\nexcept SSRFError as e:\n    if \"DNS resolution failed\" in str(e):\n        raise HTTPException(status_code=400, detail=\"Could not resolve host in URL\")\n    raise","handlingStrategy":"try-catch","validationCode":"import socket\n\ndef host_resolves(url: str) -> bool:\n    from urllib.parse import urlparse\n    host = urlparse(url).hostname\n    if not host:\n        return False\n    try:\n        socket.getaddrinfo(host, 443, proto=socket.IPPROTO_TCP)\n        return True\n    except socket.gaierror:\n        return False\n\nif not host_resolves(user_url):\n    raise HTTPException(status_code=400, detail=\"URL host does not resolve\")","typeGuard":null,"tryCatchPattern":"from litellm.litellm_core_utils.url_utils import SSRFError\n\ntry:\n    resp = safe_get(client, user_url)\nexcept SSRFError as e:\n    if \"DNS resolution failed\" in str(e):\n        raise HTTPException(status_code=400, detail=\"Could not resolve host in URL\")\n    raise","preventionTips":["Verify from the proxy host (not your laptop) that user-supplied domains resolve: getent hosts <name>.","Monitor DNS health in the proxy container; gaierror often means resolver misconfiguration, not bad input.","Surface DNS failures as 4xx to the caller so they can fix the URL."],"tags":["ssrf","dns","network","url-validation"],"backgroundTag":"dns-resolution-failure","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}