{"record":{"id":"c4e1762659d52228","repo":"microsoft/semantic-kernel","slug":"the-request-uri-url-is-not-allowed-because-it","errorCode":null,"errorMessage":"The request URI '{url}' is not allowed because it is not a valid absolute URI.","messagePattern":"The request URI '(.+?)' is not allowed because it is not a valid absolute URI\\.","errorType":"exception","errorClass":"FunctionExecutionException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/openapi_plugin/server_url_validator.py","lineNumber":42,"sourceCode":"    allow_private_network_access: bool = False\n\n    def model_post_init(self, __context: Any) -> None:\n        \"\"\"Validate configured allowed base URLs.\"\"\"\n        for allowed_base_url in self.allowed_base_urls:\n            _parse_absolute_url(allowed_base_url, option_name=\"allowed_base_urls\")\n\n\nasync def validate_server_url(\n    url: str,\n    options: ServerUrlValidationOptions | None = None,\n    dns_resolver: DnsResolver | None = None,\n) -> None:\n    \"\"\"Validate a fully resolved OpenAPI operation URL against the supplied policy.\"\"\"\n    options = options or ServerUrlValidationOptions()\n    try:\n        parsed_url = _parse_absolute_url(url)\n    except ValueError as exc:\n        raise FunctionExecutionException(\n            f\"The request URI '{url}' is not allowed because it is not a valid absolute URI.\"\n        ) from exc\n\n    if _matches_allowed_base_url(parsed_url, options.allowed_base_urls):\n        return\n\n    if options.allowed_base_urls:\n        raise FunctionExecutionException(\n            f\"The request URI '{url}' is not allowed. It does not match any of the allowed base URLs.\"\n        )\n\n    if parsed_url.scheme.lower() != DEFAULT_ALLOWED_SCHEME:\n        raise FunctionExecutionException(\n            f\"The request URI scheme '{parsed_url.scheme}' is not allowed. \"\n            f\"Only '{DEFAULT_ALLOWED_SCHEME}' is permitted by default. \"\n            \"To allow this URL, add it to server_url_validation_allowed_base_urls.\"\n        )\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/openapi_plugin/server_url_validator.py#L24-L60","documentation":"`validate_server_url` is the SSRF guard. It first tries `_parse_absolute_url(url)`; if that raises `ValueError` (the URL is not a valid absolute URI), it is wrapped as `FunctionExecutionException` with this message. This is the earliest validation step — before allowlist, scheme, and DNS checks.","triggerScenarios":"Passing a URL to an OpenAPI operation whose final resolved form is not absolute (no scheme, no host, or malformed) — e.g. a server URL that was a relative path with no base, an empty string, or a value with invalid characters. Also if `server_url_override` produces a relative URL after substitution.","commonSituations":"Spec defines only a relative server (`url: /`) and no `api_host_url` / override was supplied; a path-template substitution produced a malformed URL; `server_url_override` set to a non-absolute value that slipped past `model_post_init`; templated server variables left unsubstituted.","solutions":["Provide `server_url_override` (a full absolute URL) in `OpenAPIFunctionExecutionParameters` so the resolved operation URL is absolute.","Ensure the spec's `servers` entries are absolute URLs, or pass `document_uri` so `api_host_url` can be derived.","Log the resolved URL before invocation to see what is being validated.","If the URL comes from path templating, verify all path/variable substitutions produce a well-formed absolute URL."],"exampleFix":"# before\nparams = OpenAPIFunctionExecutionParameters()  # spec has only servers: [{url: '/'}]\nawait runner.run_operation(op, args, options)  # resolved url '/' -> raises 1499\n\n# after\nparams = OpenAPIFunctionExecutionParameters(server_url_override=\"https://api.example.com\")\nawait runner.run_operation(op, args, options)","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nfrom semantic_kernel.connectors.openapi_plugin.server_url_validator import (\n    validate_server_url, ServerUrlValidationOptions,\n)\n\ndef ensure_absolute(url: str) -> str:\n    p = urlparse(url)\n    if not p.scheme or not p.netloc:\n        raise ValueError(f\"Resolved URL is not absolute: {url!r}\")\n    return url\n\nresolved = ensure_absolute(operation.build_operation_url(arguments, override, host))\nawait validate_server_url(resolved, options)","typeGuard":"def is_absolute_url(value: str) -> bool:\n    p = urlparse(value)\n    return bool(p.scheme in (\"http\", \"https\") and p.netloc)","tryCatchPattern":"from semantic_kernel.exceptions import FunctionExecutionException\n\ntry:\n    await runner.run_operation(op, args, options)\nexcept FunctionExecutionException as e:\n    if \"not a valid absolute URI\" in str(e):\n        # supply server_url_override / document_uri, then retry\n        params = OpenAPIFunctionExecutionParameters(server_url_override=\"https://api.example.com\")\n        raise\n    raise","preventionTips":["Always set `server_url_override` or an absolute `servers` entry in the spec.","Pass `document_uri` so a base can be derived when servers are relative.","Validate the resolved URL with `validate_server_url` before invoking.","Log resolved URLs in dev to catch templating/substitution bugs."],"tags":["openapi-plugin","ssrf","url-validation","semantic-kernel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}