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

  1. 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.
  2. Fix typos or stale hostnames in the URL/env var.
  3. For internal-only names, add them to `allowed_hosts` (they then skip DNS validation by design).
  4. 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

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

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/430b8c572890aaad. Report an issue: GitHub.