{"record":{"id":"4c5034dc2d83e8ce","repo":"langchain-ai/langchain","slug":"dns-resolution-returned-no-results","errorCode":null,"errorMessage":"DNS resolution returned no results","messagePattern":"DNS resolution returned no results","errorType":"exception","errorClass":"SSRFBlockedError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/_security/_transport.py","lineNumber":88,"sourceCode":"        if hostname.lower() in allowed:\n            return await self._inner.handle_async_request(request)\n\n        # 4. DNS resolution\n        port = request.url.port or (443 if scheme == \"https\" else 80)\n        try:\n            addrinfo = await asyncio.to_thread(\n                socket.getaddrinfo,\n                hostname,\n                port,\n                type=socket.SOCK_STREAM,\n            )\n        except socket.gaierror as exc:\n            msg = \"DNS resolution failed\"\n            raise SSRFBlockedError(msg) from exc\n\n        if not addrinfo:\n            msg = \"DNS resolution returned no results\"\n            raise SSRFBlockedError(msg)\n\n        # 5. Validate ALL resolved IPs - any blocked means reject.\n        for _family, _type, _proto, _canonname, sockaddr in addrinfo:\n            ip_str: str = sockaddr[0]  # type: ignore[assignment]\n            validate_resolved_ip(ip_str, self._policy)\n\n        # 6. Pin to first resolved IP.\n        pinned_ip = addrinfo[0][4][0]\n\n        # 7. Rewrite URL to use pinned IP, preserving Host header and SNI.\n        pinned_url = request.url.copy_with(host=pinned_ip)\n\n        # Build extensions dict, adding sni_hostname for HTTPS so TLS\n        # certificate validation uses the original hostname.\n        extensions = dict(request.extensions)\n        if scheme == \"https\":\n            extensions[\"sni_hostname\"] = hostname.encode(\"ascii\")\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/_security/_transport.py#L70-L106","documentation":"After a successful `getaddrinfo` call, the async SSRF transport requires a non-empty address list; an empty result raises `SSRFBlockedError('DNS resolution returned no results')`. This is a defensive branch — `getaddrinfo` normally raises rather than returning empty — and indicates a resolver behaving oddly.","triggerScenarios":"An exotic resolver/mocked `getaddrinfo` returning `[]`; unusual platform resolver behavior (some sandbox wrappers, glibc edge cases, or monkeypatched sockets in tests) yielding no addresses for the port/type combination.","commonSituations":"Test suites that patch `socket.getaddrinfo` incompletely; custom DNS shims or LD_PRELOAD resolvers; rare Nsswitch/mDNS configurations.","solutions":["If you mock or wrap `socket.getaddrinfo` in tests, return a realistic non-empty addrinfo list","Check `getent hosts <hostname>` / `socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)` in the failing environment to see what the resolver actually returns","Eliminate custom resolver shims (LD_PRELOAD, nsswitch overrides) or fix them to return addresses","Retry in case of transient resolver weirdness; escalate to infrastructure if persistent"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import socket\n\ndef resolver_healthy(host: str, port: int) -> bool:\n    try:\n        return len(socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)) > 0\n    except OSError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    resp = await client.get(url)\nexcept SSRFBlockedError as e:\n    if 'returned no results' in str(e):\n        # resolver behaved abnormally; log and surface infra issue\n        logger.error('resolver returned empty for %s', url)\n    raise","preventionTips":["Never mock getaddrinfo with [] in tests — return realistic tuples","Avoid custom resolver shims unless they preserve the standard contract","Watch for this message as a canary for broken resolver wrappers"],"tags":["ssrf","httpx","dns","async","edge-case"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}