docling-project/docling · error · ValueError

URL must contain a valid hostname

Error message

URL must contain a valid hostname

What it means

ValueError from validate_url_safety (docling/backend/utils/image_resource_loader.py) when a URL parsed with urlparse() has no hostname. It is the first stage of SSRF protection for remotely fetched images referenced by documents (e.g. HTML backends) before any DNS resolution or HTTP request occurs.

Source

Thrown at docling/backend/utils/image_resource_loader.py:54

def validate_url_safety(url: str) -> None:
    """Reject URLs that resolve to a non-public IP address.

    Guards against SSRF by requiring the URL's host to resolve to a globally
    routable address. Private, loopback, link-local, reserved, multicast, and
    unspecified addresses are refused.

    Args:
        url: The URL whose host is validated.

    Raises:
        ValueError: If the URL has no hostname, the hostname cannot be
            resolved, or it resolves to a restricted (non-global) IP address.
    """
    parsed = urlparse(url)
    hostname = parsed.hostname

    if not hostname:
        raise ValueError("URL must contain a valid hostname")

    try:
        ip = ipaddress.ip_address(hostname)
    except ValueError:
        try:
            ip_str = socket.gethostbyname(hostname)
            ip = ipaddress.ip_address(ip_str)
        except (socket.gaierror, socket.herror) as e:
            raise ValueError(f"Cannot resolve hostname: {hostname}") from e

    if not (
        ip.is_global
        and not (
            ip.is_private
            or ip.is_loopback
            or ip.is_link_local
            or ip.is_reserved
            or ip.is_multicast

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Supply a proper base_path/base URL when converting so relative image srcs are resolved with urljoin before fetching.
  2. Fix the document's image references to absolute http(s) URLs.
  3. Catch ValueError around conversion of untrusted HTML and log the offending src.

Example fix

# before
loader.load_image_data('images/pic.png', None)  # ValueError: no hostname

# after
abs_loc = loader.resolve_relative_path('images/pic.png', 'https://example.com/page.html')
data = loader.load_image_data(abs_loc, 'https://example.com/page.html')
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse
p = urlparse(url)
if not p.hostname:
    raise ValueError(f'image URL lacks hostname: {url}')

Type guard

def has_hostname(url: str) -> bool:
    return urlparse(url).hostname is not None

Try / catch

from urllib.parse import urlparse
if not urlparse(src).hostname:
    continue  # skip malformed image reference
loader.load_image_data(src, base)

Prevention

When it happens

Trigger: A document references an image with a malformed URL such as '/img/logo.png', 'mailto:x@y', 'file:///tmp/x.png', or 'http:///path' (empty host), and remote fetching is enabled so validate_url_safety runs.

Common situations: HTML/ODT sources with relative or scheme-relative image srcs that were not resolved against a base URL before loading; hand-authored documents with typos in image links.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/c0310d0d95fb348f. Report an issue: GitHub.