langchain-ai/langchain · error · SSRFBlockedError
missing hostname
Error message
missing hostname
What it means
Raised by `validate_url_sync` when `urllib.parse.urlparse(url).hostname` is empty — the URL parses but has no host component, so hostname-level policy checks cannot run and the guard fails closed. Typical shapes are scheme-only URLs, opaque URIs, or relative paths where the authority component (`//host`) is absent.
Source
Thrown at libs/core/langchain_core/_security/_policy.py:297
"""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:
msg = f"scheme '{scheme}' not allowed"
raise SSRFBlockedError(msg)
hostname = parsed.hostname
if not hostname:
msg = "missing hostname"
raise SSRFBlockedError(msg)
allowed = _effective_allowed_hosts(policy)
if hostname.lower() in {h.lower() for h in allowed}:
return
try:
ipaddress.ip_address(hostname)
validate_resolved_ip(hostname, policy)
except SSRFBlockedError:
raise
except ValueError:
pass
else:
return
validate_hostname(hostname, policy)
View on GitHub (pinned to e32fa9a52e)
Solutions
- Fix the URL construction: ensure base URL is present and joined properly (`urljoin(base, path)`), producing e.g. `https://host/api/thing`.
- Reject host-less URLs at input validation (they are not fetchable anyway).
- If opaque schemes like mailto: are valid input for your field, validate them with a different rule instead of the SSRF fetch validator.
Example fix
# before
url = '/v1/chat' # base URL lost
validate_url_sync(url, policy) # missing hostname
# after
from urllib.parse import urljoin
url = urljoin('https://api.example.com', '/v1/chat')
validate_url_sync(url, policy) Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def has_hostname(url: str) -> bool:
return bool(urlparse(url).hostname) Try / catch
from langchain_core._security._policy import SSRFBlockedError
try:
validate_url_sync(url, policy)
except SSRFBlockedError as e:
if str(e) == "missing hostname":
url = urljoin(settings.base_url, url) # repair relative path and revalidate
validate_url_sync(url, policy)
else:
raise Prevention
- Always build fetch URLs with urljoin(base_url, path) so a host is guaranteed.
- Validate URL shape (scheme + host) at input time with a 4xx response for user data.
- Treat relative URLs in config as a base-url wiring bug, not an SSRF event.
When it happens
Trigger: `validate_url_sync('mailto:user@x.com')`, `validate_url_sync('/relative/path')`, `validate_url_sync('https:///path')` (empty authority), or `validate_url_sync('javascript:alert(1)')` after widening allowed_schemes. Note ordering: the scheme check runs first, so a non-allowed scheme on the same URL raises 'scheme ... not allowed' instead.
Common situations: Config/env-var URLs missing the host ('https:///api'), relative endpoint paths concatenated in the wrong order (base omitted), or user input like an email `mailto:` link fed into a URL-fetch validator. Also common in tests using path-only fixtures.
Related errors
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/a7198766c3a795ef.
Report an issue: GitHub.