lfnovo/open-notebook · error · ValueError

Could not resolve hostname '{hostname}' for outbound request

Error message

Could not resolve hostname '{hostname}' for outbound request.

What it means

The hostname passed DNS resolution through socket.getaddrinfo but it raised socket.gaierror (name or service not known, or resolver failure). Since the SSRF pinning layer needs at least one IP to vet and pin, an unresolvable host aborts the outbound request. The original gaierror is chained for debugging.

Source

Thrown at open_notebook/utils/url_validation.py:151

        )

    hostname = parsed.hostname
    if not hostname:
        raise ValueError("Invalid URL: hostname could not be determined.")

    try:
        ip = ipaddress.ip_address(hostname)
        _reject_dangerous_ip(ip, hostname)
        # Already an IP literal — no rewrite / Host / SNI override needed.
        return PinnedHttpTarget(url=url.strip())
    except ValueError as ve:
        if "Link-local" in str(ve) or "Invalid URL" in str(ve) or "metadata" in str(ve):
            raise

    try:
        safe_ips = await _resolve_safe_ips(hostname)
    except socket.gaierror as exc:
        raise ValueError(
            f"Could not resolve hostname '{hostname}' for outbound request."
        ) from exc

    if not safe_ips:
        raise ValueError(
            f"Could not resolve hostname '{hostname}' for outbound request."
        )

    # Prefer IPv4 when available (simpler URL form; same vetted set).
    pinned_ip = next((ip for ip in safe_ips if ":" not in ip), safe_ips[0])
    host_for_url = f"[{pinned_ip}]" if ":" in pinned_ip else pinned_ip
    # HTTP Host / TLS SNI must be ASCII; IDNA-encode internationalized names.
    ascii_hostname = hostname.encode("idna").decode("ascii")
    if parsed.port is not None:
        netloc = f"{host_for_url}:{parsed.port}"
        host_header = f"{ascii_hostname}:{parsed.port}"
    else:
        netloc = host_for_url

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Verify the hostname resolves from the same machine/container: `getent hosts <hostname>` or `nslookup <hostname>`
  2. Fix typos in the configured hostname
  3. If the host is internal, run the service where that DNS name resolves (VPN, docker network alias, or compose service name)
  4. Check container DNS settings (docker --dns, compose dns: block) if resolution works on the host but not inside the container

Example fix

# before
await _test_ollama_connection("http://ollama-host:11434")  # name not in this network
# after (docker-compose service name)
await _test_ollama_connection("http://ollama:11434")
Defensive patterns

Strategy: try-catch

Validate before calling

import socket

def hostname_resolves(host: str) -> bool:
    try:
        socket.getaddrinfo(host, None)
        return True
    except socket.gaierror:
        return False

Try / catch

try:
    target = await prepare_pinned_http_target(url, provider)
except ValueError as e:
    if "Could not resolve hostname" in str(e):
        return {"status": "unreachable", "hint": "check DNS / VPN / typo"}
    raise

Prevention

When it happens

Trigger: Calling discover_with_config or a connection-test helper with a hostname that doesn't exist (typo like 'api.openai.co'), a resolver outage, or an internal-only DNS name from a machine outside that network.

Common situations: Typo'd provider hostname in config; on-prem/Ollama host name only resolvable inside the company VPN; container where the DNS server is unreachable; /etc/hosts entry forgotten when migrating to Docker.

Understand the failure class

Related errors


AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27). Data as JSON: /api/errors/ce729a16c9ad0efe. Report an issue: GitHub.