{"record":{"id":"4dc2f81936167b32","repo":"oobabooga/textgen","slug":"could-not-resolve-hostname-hostname","errorCode":null,"errorMessage":"Could not resolve hostname: {hostname}","messagePattern":"Could not resolve hostname: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"modules/web_search.py","lineNumber":40,"sourceCode":"    parsed = urlparse(url)\n    if parsed.scheme not in ('http', 'https'):\n        raise ValueError(f\"Unsupported URL scheme: {parsed.scheme}\")\n\n    if '@' in parsed.netloc:\n        raise ValueError(\"Invalid URL: userinfo (credentials) in URLs is not allowed\")\n\n    hostname = parsed.hostname\n    if not hostname:\n        raise ValueError(\"No hostname in URL\")\n\n    # Resolve hostname and check all returned addresses\n    try:\n        for family, _, _, _, sockaddr in socket.getaddrinfo(hostname, None):\n            ip = ipaddress.ip_address(sockaddr[0])\n            if not ip.is_global:\n                raise ValueError(f\"Access to non-public address {ip} is blocked\")\n    except socket.gaierror:\n        raise ValueError(f\"Could not resolve hostname: {hostname}\")\n\n\ndef safe_get(url, headers=None, timeout=10, max_redirects=5):\n    \"\"\"Fetch a URL with SSRF-safe redirect handling. Validates every hop.\"\"\"\n    _validate_url(url)\n    for _ in range(max_redirects):\n        response = requests.get(url, headers=headers, timeout=timeout, allow_redirects=False)\n        if response.is_redirect and 'Location' in response.headers:\n            url = urljoin(url, response.headers['Location'])\n            _validate_url(url)\n        else:\n            return response\n\n    raise ValueError(f\"Too many redirects (max {max_redirects})\")\n\n\ndef get_current_timestamp():\n    \"\"\"Returns the current time in 24-hour format\"\"\"","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/oobabooga/textgen/blob/ed888c71f221df552750e1834b3654abab8ae345/modules/web_search.py#L22-L58","documentation":"Raised by _validate_url() when socket.getaddrinfo() raises socket.gaierror while resolving the URL hostname — i.e. DNS lookup failed (NXDOMAIN, no resolver, offline, or malformed host). The guard must resolve the host to check it against private ranges, so an unresolvable name is treated as invalid rather than being passed through to the HTTP client.","triggerScenarios":"Fetching a URL with a typo'd or non-existent domain ('https://exmaple.com'), a host only resolvable on an internal DNS the process cannot reach, running in a sandbox/container without network access, or a transient resolver failure.","commonSituations":"Typos in hostnames; expired/dead domains in search results or feeds; air-gapped or DNS-restricted containers; VPN split-DNS where the name only resolves inside the VPN but the process runs outside it.","solutions":["Verify the hostname with dig/getent hosts <host> from the same machine/container the app runs on.","Fix typos or use a different mirror for dead domains.","If in a container, ensure it has working DNS (docker --dns, correct resolv.conf).","Retry once after a transient resolver blip, but stop and report if it persists."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import socket\nfrom urllib.parse import urlparse\n\ndef hostname_resolves(url: str) -> bool:\n    host = urlparse(url).hostname\n    if not host:\n        return False\n    try:\n        socket.getaddrinfo(host, None)\n        return True\n    except socket.gaierror:\n        return False","typeGuard":null,"tryCatchPattern":"import socket\n\nfor attempt in range(2):  # one retry for transient resolver blips\n    try:\n        resp = safe_get(url)\n        break\n    except ValueError as e:\n        if 'Could not resolve hostname' in str(e) and attempt == 0:\n            continue\n        raise","preventionTips":["Verify hostnames with getent/dig from the same network namespace before batch fetching.","Ensure containers/VMs running the app have working DNS.","Filter dead domains out of crawl lists early instead of retrying them per run."],"tags":["ssrf","dns","network","web-fetch"],"backgroundTag":null,"analyzedSha":"ed888c71f221df552750e1834b3654abab8ae345","analyzedAt":"2026-08-15T05:24:21.000Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}