langchain-ai/langchain · error · SSRFBlockedError
DNS resolution failed
Error message
DNS resolution failed
What it means
Raised by the async `validate_url` when `socket.getaddrinfo` (run via `asyncio.to_thread`) fails with `socket.gaierror` while resolving the URL's hostname. The SSRF validator must resolve DNS to check the IP, so an unresolvable name is treated as a blocked URL (SSRFBlockedError, chained from the gaierror) rather than passed through — a fail-closed design.
Source
Thrown at libs/core/langchain_core/_security/_policy.py:272
"""
parsed = urllib.parse.urlparse(url)
hostname = parsed.hostname or ""
validate_url_sync(url, policy)
allowed = {h.lower() for h in _effective_allowed_hosts(policy)}
if hostname.lower() in allowed:
return
scheme = (parsed.scheme or "").lower()
port = parsed.port or (443 if scheme == "https" else 80)
try:
addrinfo = await asyncio.to_thread(
socket.getaddrinfo, hostname, port, type=socket.SOCK_STREAM
)
except socket.gaierror as exc:
msg = "DNS resolution failed"
raise SSRFBlockedError(msg) from exc
for _family, _type, _proto, _canonname, sockaddr in addrinfo:
validate_resolved_ip(str(sockaddr[0]), policy)
def validate_url_sync(url: str, policy: SSRFPolicy = DEFAULT_SSRF_POLICY) -> None:
"""Synchronous URL validation (no DNS resolution).
Suitable for Pydantic validators and other sync contexts. Checks scheme
and hostname patterns only - use `validate_url` for full DNS-aware checking.
Raises:
SSRFBlockedError: If the URL violates the policy.
"""
parsed = urllib.parse.urlparse(url)
scheme = (parsed.scheme or "").lower()
if scheme not in policy.allowed_schemes:View on GitHub (pinned to e32fa9a52e)
Solutions
- Verify DNS from the same environment: `python -c "import socket; print(socket.getaddrinfo('host', 443, type=socket.SOCK_STREAM))"` — if this fails, fix resolver/VPN/network, not the policy.
- Fix typos or stale hostnames in the URL/env var.
- For internal-only names, add them to `allowed_hosts` (they then skip DNS validation by design).
- Retry once on transient resolver failures if your fetch layer already handles retryable network errors.
Example fix
# before
await validate_url('https://api.exmaple.com/v1', policy) # typo -> DNS resolution failed
# after
await validate_url('https://api.example.com/v1', policy) Defensive patterns
Strategy: retry
Validate before calling
import socket
def host_resolves(host: str) -> bool:
try:
socket.getaddrinfo(host, 443, type=socket.SOCK_STREAM)
return True
except socket.gaierror:
return False Try / catch
from langchain_core._security._policy import SSRFBlockedError
for attempt in range(2):
try:
await validate_url(url, policy)
break
except SSRFBlockedError as e:
if str(e) == "DNS resolution failed" and attempt == 0:
await asyncio.sleep(0.5) # transient resolver failure: retry once
continue
raise # policy blocks and persistent DNS failure are not retryable Prevention
- Pre-resolve hostnames from the runtime that will fetch (container/VPN DNS differs from your laptop).
- Add known internal hostnames to allowed_hosts — they skip DNS validation by design.
- Read the chained gaierror to tell NXDOMAIN (fix the name) from timeout (fix the network).
When it happens
Trigger: `await validate_url('https://nonexistent-host-xyz.example.com/path')` where DNS returns NXDOMAIN or times out (gaierror). Also transiently when the resolver is flaky, a VPN/captive portal blocks DNS, or the hostname only resolves via internal DNS unavailable to the process. The allowed-hosts short-circuit at the top means explicit `allowed_hosts` entries skip DNS entirely.
Common situations: CI runners without access to internal DNS; air-gapped or proxied environments; typos in base URLs in env vars; ephemeral hostnames from cloud previews that expired. Because the original gaierror is chained (`from exc`), the real cause is visible in the traceback's 'The above exception was the direct cause' section — always read it before assuming a policy block.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- Failed to resolve hostname '{hostname}': {e}
- Network error while validating URL: {e}
- DNS resolution failed
- invalid IP address
- private IP range
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/430b8c572890aaad.
Report an issue: GitHub.