invoke-ai/InvokeAI · error · UnsafeDownloadURLException

Refusing to download from '{host}': it resolves to a non-pub

Error message

Refusing to download from '{host}': it resolves to a non-public address. Set `allow_private_download_urls` in invokeai.yaml to permit downloads from loopback and private-network addresses.

What it means

As an SSRF protection, InvokeAI resolves the download URL's host and refuses to connect if the resulting IP is loopback, private, link-local, or otherwise non-public. check_address() raises UnsafeDownloadURLException for such addresses; downloads can be explicitly permitted from private addresses via config.

Source

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

            values.append(int(digits, base))
        except ValueError:
            return None

    widths = {1: (32,), 2: (8, 24), 3: (8, 8, 16), 4: (8, 8, 8, 8)}[len(values)]
    if any(value >= 1 << width for value, width in zip(values, widths, strict=True)):
        return None

    address = 0
    for value, width in zip(values, widths, strict=True):
        address = (address << width) | value
    return ipaddress.IPv4Address(address)


def check_address(ip: IpAddress, host: str) -> None:
    """Raise if `ip` is not an address we are willing to connect to."""
    if _is_blocked(ip):
        logger.warning("Blocked download host %s resolving to non-public address %s", host, ip)
        raise UnsafeDownloadURLException(
            f"Refusing to download from '{host}': it resolves to a non-public address. "
            "Set `allow_private_download_urls` in invokeai.yaml to permit downloads from loopback "
            "and private-network addresses."
        )


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))

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. If the private source is intended, set allow_private_download_urls: true in invokeai.yaml
  2. Use a public URL for the model download
  3. Download the model manually into the models directory and import it locally
  4. Verify DNS resolution of the host; if it unexpectedly resolves private, fix DNS or use the correct public hostname

Example fix

// before (invokeai.yaml)
# allow_private_download_urls not set
url = 'http://localhost:8080/model.safetensors'  # UnsafeDownloadURLException
// after (invokeai.yaml)
allow_private_download_urls: true
Defensive patterns

Strategy: validation

Validate before calling

import socket, ipaddress

def is_public_host(url):
    host = urlparse(url).hostname
    for info in socket.getaddrinfo(host, None):
        ip = ipaddress.ip_address(info[4][0])
        if not ip.is_global:
            return False
    return True

Try / catch

from invokeai.app.util.ssrf import UnsafeDownloadURLException
try:
    download(url)
except UnsafeDownloadURLException as e:
    if 'non-public address' in str(e):
        # either switch to a public URL or set allow_private_download_urls in invokeai.yaml
        ...
    else:
        raise

Prevention

When it happens

Trigger: Downloading a model from a URL whose hostname resolves to 127.0.0.1, 10.x, 192.168.x, 169.254.x, or any mapped non-public address while allow_private_download_urls is false (default).

Common situations: Pointing InvokeAI at a local mirror/proxy like http://localhost:8080/model.safetensors or an internal network NAS; testing with a local model server; DNS rebinding to a private IP.

Related errors


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