HumanSignal/label-studio · error · LabelStudioAPIException

Can't resolve hostname {domain}

Error message

Can't resolve hostname {domain}

What it means

validate_url_for_ssrf resolves the URL's hostname via socket.gethostbyname as the first step of SSRF protection. If DNS resolution fails (socket.error), it wraps the failure in a LabelStudioAPIException: "Can't resolve hostname {domain}". This prevents proceeding to IP-based checks on an unresolvable host.

Source

Thrown at label_studio/core/utils/io.py:199

          and the URL resolves to a local address.
        - LabelStudioApiException if the hostname cannot be resolved

    :param url: Url to be checked for validity/safety,
    :param block_local_urls: Whether urls that resolve to local/private networks should be allowed.
    """

    parsed_url = parse_url(url)

    if parsed_url.scheme not in ('http', 'https'):
        raise SsrfBlockedUrlError

    domain = parsed_url.host
    try:
        ip = socket.gethostbyname(domain)
    except socket.error:
        from core.utils.exceptions import LabelStudioAPIException

        raise LabelStudioAPIException(f"Can't resolve hostname {domain}")

    if block_local_urls:
        validate_ip(ip)


def validate_upload_url(url, block_local_urls=True):
    """Backward-compatible wrapper around validate_url_for_ssrf."""
    return validate_url_for_ssrf(url, block_local_urls=block_local_urls)


def validate_ip(ip: str) -> None:
    """If settings.USE_DEFAULT_BANNED_SUBNETS is True, this function checks
    if an IP is reserved for any of the reasons in
    https://en.wikipedia.org/wiki/Reserved_IP_addresses
    and raises an exception if so. Additionally, if settings.USER_ADDITIONAL_BANNED_SUBNETS
    is set, it will also check against those subnets.

    If settings.USE_DEFAULT_BANNED_SUBNETS is False, this function will only check

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Check the hostname in the URL for typos and confirm it resolves: run `nslookup <domain>` or `getent hosts <domain>` from the same host/container.
  2. Fix DNS configuration in your container/network (resolv.conf, CoreDNS, VPN to the private zone).
  3. If the target is an internal service, verify the service name matches the compose/k8s service DNS name.
  4. For S3 endpoints, confirm the endpoint URL is correct and reachable from the Label Studio container.

Example fix

// before
validate_url_for_ssrf("https://minio.internal.svc:9000/bucket")  # DNS fails
// after — verify and use the reachable name
validate_url_for_ssrf("https://minio.default.svc.cluster.local:9000/bucket")
Defensive patterns

Strategy: try-catch

Validate before calling

import socket
from urllib.parse import urlparse
try:
    socket.gethostbyname(urlparse(url).hostname)
except socket.error:
    raise ValueError(f'Cannot resolve hostname {urlparse(url).hostname}')

Type guard

def hostname_resolves(url: str) -> bool:
    try:
        host = urlparse(url).hostname
        return bool(host) and socket.gethostbyname(host) is not None
    except socket.error:
        return False

Try / catch

try:
    validate_upload_url(url, block_local_urls=True)
except LabelStudioAPIException as e:
    if "Can't resolve hostname" in str(e):
        return Response({'error': str(e), 'hint': 'Check DNS / hostname spelling'}, status=400)
    raise

Prevention

When it happens

Trigger: Calling validate_url_for_ssrf (directly or via validate_upload_url, ssrf_safe_request, validate_s3_endpoint, validate_url) with a URL whose host cannot be resolved by DNS — bad hostname, no DNS in the container, offline environment, or stale internal hostname.

Common situations: S3/storage endpoints with typos in the hostname; Docker containers lacking DNS access to internal service names; hosts file entries removed; resolving private names that only exist in another network.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/86a43341895126f5. Report an issue: GitHub.