{"record":{"id":"fce25b9d69bb6249","repo":"ComposioHQ/composio","slug":"could-not-resolve-host-parsed-hostname","errorCode":null,"errorMessage":"Could not resolve host \"{parsed.hostname}\"","messagePattern":"Could not resolve host \"(.+?)\"","errorType":"exception","errorClass":"BlockedInternalUrlError","httpStatus":null,"severity":"error","filePath":"python/composio/utils/url_safety.py","lineNumber":103,"sourceCode":"        prepared_url = requests.Request(method=\"GET\", url=url).prepare().url\n        if prepared_url is None:\n            raise ValueError(\"Prepared URL is missing\")\n        parsed = urlparse(prepared_url)\n        if parsed.scheme not in {\"http\", \"https\"} or not parsed.hostname:\n            raise ValueError(\"URL must use HTTP(S) and include a hostname\")\n    except (requests.exceptions.RequestException, ValueError):\n        raise BlockedInternalUrlError(\n            \"Refusing to fetch a malformed or non-http(s) URL\"\n        ) from None\n\n    try:\n        # Resolver order is kept: it encodes the system's address preference\n        # (RFC 6724), and connecting walks it the way urllib3 would.\n        addresses: t.List[str] = []\n        for result in socket.getaddrinfo(parsed.hostname, None):\n            address = result[4][0]\n            if not isinstance(address, str):\n                raise BlockedInternalUrlError(\n                    f'Could not resolve host \"{parsed.hostname}\"'\n                )\n            if address not in addresses:\n                addresses.append(address)\n    except socket.gaierror as error:\n        raise BlockedInternalUrlError(\n            f'Could not resolve host \"{parsed.hostname}\"'\n        ) from error\n\n    for address in addresses:\n        if is_blocked_ip(address):\n            raise BlockedInternalUrlError(\n                f'Refusing to fetch \"{parsed.hostname}\" because it resolves to a non-public address'\n            )\n\n    if not addresses:\n        raise BlockedInternalUrlError(f'Could not resolve host \"{parsed.hostname}\"')\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/utils/url_safety.py#L85-L121","documentation":"Raised by assert_safe_fetch_target when DNS resolution via socket.getaddrinfo returns an address entry that is not a plain string (unexpected getaddrinfo shape). It is a fail-closed guard in the SSRF-protection layer: any ambiguity in the resolved address is treated as unsafe and blocks the fetch with BlockedInternalUrlError.","triggerScenarios":"Calling safe_request (or _pinned_request) with a URL whose hostname resolution returns a non-string sockaddr (exotic resolver/IPv6 sandbox setups). Effectively unreachable on normal CPython resolvers.","commonSituations":"Custom DNS resolvers, patched socket modules, or test environments mocking getaddrinfo incorrectly.","solutions":["Verify how getaddrinfo is being mocked/patched in tests; return tuples whose result[4][0] is a string IP","Check for socket monkey-patching (e.g. gevent, eventlet) or unusual resolver configurations","Avoid hostnames that resolve via non-standard resolver backends when using safe_request"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    safe_request('GET', url)\nexcept BlockedInternalUrlError as e:\n    # resolution guard tripped; log and skip\n    log.warning('blocked fetch: %s', e)","preventionTips":["Avoid patching socket.getaddrinfo in processes that use safe_request","Return string IPs from resolver mocks"],"tags":["network","dns","ssrf","python"],"backgroundTag":"dns-resolution-failed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}