crewAIInc/crewAI · error · ValueError
URL has no hostname: '{url}'
Error message
URL has no hostname: '{url}' What it means
Thrown by validate_url() in crewai_tools' SSRF guard (safe_path.py) when a URL parses successfully but has no hostname component. The URL validator only permits http/https URLs that resolve to public IPs, and a missing hostname makes the DNS-based private-IP check impossible. This is a fail-fast security check, not a network error.
Source
Thrown at lib/crewai-tools/src/crewai_tools/security/safe_path.py:224
return url
parsed = urlparse(url)
# Block file:// scheme
if parsed.scheme == "file":
raise ValueError(
f"file:// URLs are not allowed: '{url}'. "
f"Use a file path instead, or set {_UNSAFE_PATHS_ENV}=true to bypass."
)
# Only allow http and https
if parsed.scheme not in ("http", "https"):
raise ValueError(
f"URL scheme '{parsed.scheme}' is not allowed. Only http and https are supported."
)
if not parsed.hostname:
raise ValueError(f"URL has no hostname: '{url}'")
try:
addrinfos = socket.getaddrinfo(
parsed.hostname, parsed.port or (443 if parsed.scheme == "https" else 80)
)
except socket.gaierror as exc:
raise ValueError(f"Could not resolve hostname: '{parsed.hostname}'") from exc
for _family, _, _, _, sockaddr in addrinfos:
ip_str = str(sockaddr[0])
if _is_private_or_reserved(ip_str):
raise ValueError(
f"URL '{url}' resolves to private/reserved IP {ip_str}. "
f"Access to internal networks is not allowed. "
f"Set {_UNSAFE_PATHS_ENV}=true to bypass."
)
return urlView on GitHub (pinned to 754d7323be)
Solutions
- Inspect the exact URL string being passed and fix the malformed host segment (ensure scheme is followed by a non-empty hostname, e.g. 'https://example.com/path').
- If the URL is built dynamically, log or assert the host component is non-empty before constructing the URL.
- If you genuinely need to load a local file, pass a file path instead of a file:// URL (the guard also rejects file:// separately).
- As a last-resort bypass in trusted environments only, set the documented unsafe-paths env var (referenced by _UNSAFE_PATHS_ENV) to 'true'.
Example fix
// before
url = f"http://{base_host}/data" # base_host is '' -> 'http:///data'
# after
if not base_host:
raise ValueError("base_host must be set")
url = f"http://{base_host}/data" 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
try:
validate_url(url)
except ValueError as e:
if "no hostname" in str(e):
# fix the URL string, do not retry unchanged
raise ValueError(f"Malformed URL, missing host: {url!r}") from e
raise Prevention
- Never build URLs by naive f-string concatenation without asserting the host segment is non-empty.
- Validate URLs with urlparse() (scheme in {http,https} and hostname truthy) before passing them to crewai fetch tools.
- Sanitize LLM-provided URLs through the same validation before use.
When it happens
Trigger: Calling a tool that fetches URLs (or validate_url directly) with strings like 'http:///path', 'https://:8443/x', 'http:///index.html', or a URL built by string concatenation where the host segment was empty or dropped (e.g. f"http://{host}/api" with host='').
Common situations: Building URLs from templates or config where the host variable is empty/None; stripping a hostname during URL sanitization; copy-paste typos with double slashes after the scheme; test fixtures using placeholder URLs without hosts.
Related errors
- URL scheme '{parsed.scheme}' is not allowed. Only http and h
- file:// URLs are not allowed: '{url}'. Use a file path inste
- URL '{url}' resolves to private/reserved IP {ip_str}. Access
- Blocked unsafe {label}: {e}
- Blocked unsafe URL: {e}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/98ff0a5f8eaf15f4.
Report an issue: GitHub.