{"record":{"id":"86a43341895126f5","repo":"HumanSignal/label-studio","slug":"can-t-resolve-hostname-domain","errorCode":null,"errorMessage":"Can't resolve hostname {domain}","messagePattern":"Can't resolve hostname (.+?)","errorType":"exception","errorClass":"LabelStudioAPIException","httpStatus":null,"severity":"error","filePath":"label_studio/core/utils/io.py","lineNumber":199,"sourceCode":"          and the URL resolves to a local address.\n        - LabelStudioApiException if the hostname cannot be resolved\n\n    :param url: Url to be checked for validity/safety,\n    :param block_local_urls: Whether urls that resolve to local/private networks should be allowed.\n    \"\"\"\n\n    parsed_url = parse_url(url)\n\n    if parsed_url.scheme not in ('http', 'https'):\n        raise SsrfBlockedUrlError\n\n    domain = parsed_url.host\n    try:\n        ip = socket.gethostbyname(domain)\n    except socket.error:\n        from core.utils.exceptions import LabelStudioAPIException\n\n        raise LabelStudioAPIException(f\"Can't resolve hostname {domain}\")\n\n    if block_local_urls:\n        validate_ip(ip)\n\n\ndef validate_upload_url(url, block_local_urls=True):\n    \"\"\"Backward-compatible wrapper around validate_url_for_ssrf.\"\"\"\n    return validate_url_for_ssrf(url, block_local_urls=block_local_urls)\n\n\ndef validate_ip(ip: str) -> None:\n    \"\"\"If settings.USE_DEFAULT_BANNED_SUBNETS is True, this function checks\n    if an IP is reserved for any of the reasons in\n    https://en.wikipedia.org/wiki/Reserved_IP_addresses\n    and raises an exception if so. Additionally, if settings.USER_ADDITIONAL_BANNED_SUBNETS\n    is set, it will also check against those subnets.\n\n    If settings.USE_DEFAULT_BANNED_SUBNETS is False, this function will only check","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/core/utils/io.py#L181-L217","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the hostname in the URL for typos and confirm it resolves: run `nslookup <domain>` or `getent hosts <domain>` from the same host/container.","Fix DNS configuration in your container/network (resolv.conf, CoreDNS, VPN to the private zone).","If the target is an internal service, verify the service name matches the compose/k8s service DNS name.","For S3 endpoints, confirm the endpoint URL is correct and reachable from the Label Studio container."],"exampleFix":"// before\nvalidate_url_for_ssrf(\"https://minio.internal.svc:9000/bucket\")  # DNS fails\n// after — verify and use the reachable name\nvalidate_url_for_ssrf(\"https://minio.default.svc.cluster.local:9000/bucket\")","handlingStrategy":"try-catch","validationCode":"import socket\nfrom urllib.parse import urlparse\ntry:\n    socket.gethostbyname(urlparse(url).hostname)\nexcept socket.error:\n    raise ValueError(f'Cannot resolve hostname {urlparse(url).hostname}')","typeGuard":"def hostname_resolves(url: str) -> bool:\n    try:\n        host = urlparse(url).hostname\n        return bool(host) and socket.gethostbyname(host) is not None\n    except socket.error:\n        return False","tryCatchPattern":"try:\n    validate_upload_url(url, block_local_urls=True)\nexcept LabelStudioAPIException as e:\n    if \"Can't resolve hostname\" in str(e):\n        return Response({'error': str(e), 'hint': 'Check DNS / hostname spelling'}, status=400)\n    raise","preventionTips":["Verify DNS works inside the container (getent hosts) before shipping.","Use fully-qualified internal service names (.svc.cluster.local in k8s).","Avoid hardcoding hostnames that depend on a specific VPN/network.","Pre-resolve and cache endpoints used in validation."],"tags":["network","dns","ssrf","validation"],"backgroundTag":"dns-resolution-failed","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}