microsoft/semantic-kernel · error · FunctionExecutionException
The request URI '{parsed_url.geturl()}' is not allowed: DNS
Error message
The request URI '{parsed_url.geturl()}' is not allowed: DNS resolution for host '{host}' returned no addresses. The request is blocked as a precaution. What it means
Thrown when DNS resolution for the host succeeded but returned zero addresses. The validator treats a host that resolves to nothing as suspicious and blocks the request as a precaution against SSRF.
Source
Thrown at python/semantic_kernel/connectors/openapi_plugin/server_url_validator.py:144
base_path_with_slash = base_path if base_path.endswith("/") else f"{base_path}/"
return url_path.lower().startswith(base_path_with_slash.lower())
async def _ensure_public_host(parsed_url: ParseResult, dns_resolver: DnsResolver | None) -> None:
host = parsed_url.hostname
if host is None:
raise FunctionExecutionException(f"The request URI '{parsed_url.geturl()}' does not contain a valid host.")
try:
ip_address = ipaddress.ip_address(host)
except ValueError:
addresses = await _resolve_host(host, dns_resolver)
else:
_ensure_public_address(parsed_url.geturl(), ip_address)
return
if not addresses:
raise FunctionExecutionException(
f"The request URI '{parsed_url.geturl()}' is not allowed: DNS resolution for host "
f"'{host}' returned no addresses. The request is blocked as a precaution."
)
for address in addresses:
_ensure_public_address(parsed_url.geturl(), address)
async def _resolve_host(
host: str,
dns_resolver: DnsResolver | None,
) -> list[ipaddress.IPv4Address | ipaddress.IPv6Address]:
try:
if dns_resolver:
resolved_addresses = await dns_resolver(host)
return [ipaddress.ip_address(address) for address in resolved_addresses]
loop = asyncio.get_running_loop()View on GitHub (pinned to c028a0c7dc)
Solutions
- Verify the hostname has A/AAAA records (dig a <host> / dig aaaa <host>)
- Correct the hostname typo
- If using a custom dns_resolver, ensure it returns IP address strings for valid hosts
- Add the trusted base URL to allowed_base_urls to bypass DNS checks once safety is confirmed
Defensive patterns
Strategy: try-catch
Validate before calling
import socket
def host_has_records(host: str) -> bool:
try:
return len(socket.getaddrinfo(host, None, type=socket.SOCK_STREAM)) > 0
except OSError:
return False
if not host_has_records(urlparse(url).hostname):
raise ValueError(f'{url} resolves to no addresses') Try / catch
try:
await validate_server_url(url, options)
except FunctionExecutionException as e:
if 'returned no addresses' in str(e):
# verify DNS records exist or add the host to allowed_base_urls
... Prevention
- Verify hosts have A/AAAA records before relying on them
- For custom dns_resolver, ensure it returns addresses for valid hosts
- Add trusted hosts to allowed_base_urls to bypass DNS checks
When it happens
Trigger: A syntactically valid hostname that has no A/AAAA records (stale DNS, typo'd subdomain, a domain with only MX/CNAME records). _resolve_host returns an empty list.
Common situations: Domain typo; decommissioned host; split-horizon DNS returning nothing in the current environment; a custom dns_resolver returning an empty sequence.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- The request URI host '{host}' is not allowed: DNS resolution
- The address '{address}' is not allowed for the '{operation.N
- The request URI '{url}' is not allowed because it is not a v
- The request URI '{url}' is not allowed. It does not match an
- The request URI scheme '{parsed_url.scheme}' is not allowed.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/02b414939c8bfec6.
Report an issue: GitHub.