crewAIInc/crewAI · error · ValueError

Could not resolve hostname: '{parsed.hostname}'

Error message

Could not resolve hostname: '{parsed.hostname}'

What it means

Thrown when socket.getaddrinfo() fails (raises socket.gaierror) while validating a URL's hostname in crewai_tools' SSRF guard. Before any request is made, the library resolves the hostname to check it does not point at private/reserved IPs; if DNS resolution fails, validation aborts with this ValueError. It wraps the underlying gaierror, so the original DNS error is preserved as __cause__.

Source

Thrown at lib/crewai-tools/src/crewai_tools/security/safe_path.py:231

            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 url

View on GitHub (pinned to 754d7323be)

Solutions

  1. Verify the hostname with a quick check (e.g. `python -c "import socket; print(socket.getaddrinfo('host', 443))"` or `nslookup host`) and fix typos.
  2. If the environment requires a proxy for DNS/egress, configure it so direct resolution works, or resolve and validate connectivity from the same container/host the tool runs in.
  3. Check /etc/resolv.conf or container DNS settings if the host is genuinely resolvable elsewhere.
  4. Handle the ValueError in the caller and surface a clear 'unresolvable host' message to the user/agent instead of retrying blindly.

Example fix

// before
body, ctype, final = fetch_url_body("https://exmaple.com/paper")

# after
try:
    body, ctype, final = fetch_url_body("https://example.com/paper")
except ValueError as e:
    if "Could not resolve hostname" in str(e):
        raise RuntimeError("Host unresolvable from this environment; check DNS/proxy") from e
    raise
Defensive patterns

Strategy: retry

Validate before calling

import socket

def resolvable(host: str, port: int = 443) -> bool:
    try:
        socket.getaddrinfo(host, port)
        return True
    except socket.gaierror:
        return False

Try / catch

try:
    validate_url(url)
except ValueError as e:
    if "Could not resolve hostname" in str(e):
        # transient DNS failures happen; retry with backoff once or twice
        time.sleep(2)
        validate_url(url)
    raise

Prevention

When it happens

Trigger: Passing a URL whose hostname does not exist (typo like 'exmaple.com'), a hostname only resolvable on an internal DNS the machine cannot reach, a machine with no network/DNS configured, or an IPv6 literal/hostname the local resolver refuses.

Common situations: CI runners with restricted DNS; air-gapped or proxy-only environments where direct DNS is blocked; typos in configured hostnames; containers with broken resolv.conf; hostnames from LLM-generated tool input.

Understand the failure class

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/4fdf84ff01f68b8f. Report an issue: GitHub.