{"record":{"id":"b03288c63d7efc00","repo":"langchain-ai/langchain","slug":"failed-to-resolve-hostname-hostname-e","errorCode":null,"errorMessage":"Failed to resolve hostname '{hostname}': {e}","messagePattern":"Failed to resolve hostname '(.+?)': (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/_security/_ssrf_protection.py","lineNumber":102,"sourceCode":"    # DNS resolution and IP validation\n    try:\n        addr_info = socket.getaddrinfo(\n            hostname,\n            parsed.port or (443 if parsed.scheme == \"https\" else 80),\n            socket.AF_UNSPEC,\n            socket.SOCK_STREAM,\n        )\n\n        for result in addr_info:\n            ip_str: str = result[4][0]  # type: ignore[assignment]\n            try:\n                _validate_resolved_ip(ip_str, policy)\n            except SSRFBlockedError as exc:\n                raise ValueError(str(exc)) from exc\n\n    except socket.gaierror as e:\n        msg = f\"Failed to resolve hostname '{hostname}': {e}\"\n        raise ValueError(msg) from e\n    except OSError as e:\n        msg = f\"Network error while validating URL: {e}\"\n        raise ValueError(msg) from e\n\n    return url_str\n\n\ndef is_safe_url(\n    url: str | AnyHttpUrl,\n    *,\n    allow_private: bool = False,\n    allow_http: bool = True,\n) -> bool:\n    \"\"\"Non-throwing version of `validate_safe_url`.\"\"\"\n    try:\n        validate_safe_url(url, allow_private=allow_private, allow_http=allow_http)\n    except ValueError:\n        return False","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/_security/_ssrf_protection.py#L84-L120","documentation":"`validate_safe_url` performs DNS resolution (`socket.getaddrinfo`) on the URL's hostname to inspect the resolved IPs; a `socket.gaierror` (name resolution failure) is wrapped in a `ValueError` with the hostname and OS error string. It means the hostname could not be resolved at validation time, before any request is made.","triggerScenarios":"Calling `validate_safe_url('http://nonexistent-host.example/x')` where DNS returns NXDOMAIN or SERVFAIL; typo'd hostnames; bare hostnames like `http://myapi/` that only resolve via search domains the process lacks; air-gapped/offline environments where the resolver is unreachable.","commonSituations":"Offline development machines or containers with no DNS; internal hostnames that resolve in one network but not another; typos in configured webhook/endpoint URLs; IPv6-only resolvers returning errors for AF_UNSPEC queries.","solutions":["Verify the hostname resolves in the same environment: `python -c \"import socket; print(socket.getaddrinfo('host', 80))\"` from the same container/host","Fix the hostname typo or use a fully-qualified domain name / IP literal where appropriate","If offline validation is expected, skip or short-circuit SSRF validation for trusted internal URLs (e.g. `allow_private=True` plus pre-resolved IPs)","Configure DNS in the container/deployment (e.g. `--dns`, CoreDNS, /etc/resolv.conf) so the name resolves"],"exampleFix":"# before\nsafe = validate_safe_url(f\"http://{os.environ['WEBHOOK_HOST']}/cb\")\n\n# after\nhost = os.environ['WEBHOOK_HOST']\ntry:\n    socket.gethostbyname(host)\nexcept socket.gaierror:\n    raise ValueError(f\"WEBHOOK_HOST {host!r} does not resolve; check DNS config\")\nsafe = validate_safe_url(f\"http://{host}/cb\")","handlingStrategy":"validation","validationCode":"import socket\n\ndef hostname_resolves(hostname: str) -> bool:\n    try:\n        socket.getaddrinfo(hostname, 443, type=socket.SOCK_STREAM)\n        return True\n    except socket.gaierror:\n        return False\n\nif not hostname_resolves(parsed.hostname):\n    raise ValueError(f\"hostname {parsed.hostname!r} unresolvable; fix DNS\")","typeGuard":null,"tryCatchPattern":"try:\n    safe = validate_safe_url(url)\nexcept ValueError as e:\n    if 'Failed to resolve hostname' in str(e):\n        # config/DNS problem, not a policy block\n        handle_dns_misconfig(url, e)\n    else:\n        raise","preventionTips":["Pre-resolve hostnames from config files at startup, not at request time","Run containers with a working resolver; test with `getent hosts <name>`","Distinguish resolution failures (gaierror text) from policy blocks in error handling"],"tags":["ssrf","security","dns","network","validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}