invoke-ai/InvokeAI · error · UnsafeDownloadURLException

Download URL '{url}' has no host.

Error message

Download URL '{url}' has no host.

What it means

After scheme validation, the URL must contain a host. urlsplit().hostname returns None for malformed or host-less URLs, and validate_download_url raises UnsafeDownloadURLException because a download target without a host cannot be resolved or connected to.

Source

Thrown at invokeai/app/util/ssrf.py:204

def validate_download_url(url: str, allow_private_urls: bool = False) -> None:
    """Reject `url` up front if it obviously points somewhere only the server can reach.

    Every address the host resolves to must be public — a hostname with both a public and a
    loopback record is rejected, because we cannot control which one the HTTP client picks.

    An unresolvable host is allowed through to the HTTP client, so that offline test
    environments and mocked sessions keep working. That is only safe because the session
    from `build_guarded_session()` re-checks the address it actually connects to.
    """
    parts = urlsplit(str(url))

    if parts.scheme.lower() not in ALLOWED_SCHEMES:
        raise UnsafeDownloadURLException(f"Unsupported URL scheme '{parts.scheme}'. Only http and https are allowed.")

    host = parts.hostname
    if not host:
        raise UnsafeDownloadURLException(f"Download URL '{url}' has no host.")

    try:
        port = parts.port
    except ValueError as e:
        raise UnsafeDownloadURLException(f"Download URL '{url}' has an invalid port.") from e

    if allow_private_urls:
        return

    for spelling in _host_spellings(host):
        literal = _parse_ipv4_literal(spelling)
        if literal is not None:
            candidates = [literal]
        else:
            try:
                candidates = _resolve(spelling, port)
            except (OSError, UnicodeError, ValueError):
                continue

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Provide a full absolute URL including scheme and host, e.g. https://host/path/file
  2. Print/inspect the URL string before calling the download API to catch mangling or truncation
  3. Use a local import path instead of the remote-download API for local files
  4. Quote URLs passed through shells to avoid stripping the host

Example fix

// before
url = 'https:///models/sd15.safetensors'  # empty host
// after
url = 'https://huggingface.co/models/sd15.safetensors'
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlsplit

def validate_host(url):
    if not urlsplit(str(url)).hostname:
        raise ValueError(f"URL has no host: {url}")

Try / catch

from invokeai.app.util.ssrf import UnsafeDownloadURLException
try:
    download(url)
except UnsafeDownloadURLException as e:
    if 'has no host' in str(e):
        raise ValueError(f"Fix the download URL, it lacks a host: {url}") from e
    raise

Prevention

When it happens

Trigger: Passing 'https:///path/model.safetensors' (empty authority), a bare path like '/models/foo.safetensors', or a malformed URL whose netloc is stripped; also spaces or invalid characters that break netloc parsing.

Common situations: String concatenation bugs building the URL (missing host segment); relative paths passed where an absolute download URL is required; URLs mangled by shell escaping.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/f2dced06f0f8d3a1. Report an issue: GitHub.