{"record":{"id":"36217a13165dd218","repo":"microsoft/semantic-kernel","slug":"the-operation-path-resolves-to-request-scheme","errorCode":null,"errorMessage":"The operation path resolves to '{request.scheme}://{request.netloc}', which does not match the configured server '{server.scheme}://{server.netloc}'.","messagePattern":"The operation path resolves to '(.+?)://(.+?)', which does not match the configured server '(.+?)://(.+?)'\\.","errorType":"exception","errorClass":"FunctionExecutionException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/openapi_plugin/models/rest_api_operation.py","lineNumber":254,"sourceCode":"\n        A selected operation path must resolve to a request on the same scheme, host, and port and\n        within the server's base path. Otherwise an absolute or authority-changing operation path\n        (for example \"https://another-host/admin\") could redirect a credential-bearing request to an\n        unintended target even though it carries no dot-segment. This complements\n        `_validate_path_segments` so operation selection, path validation, and request construction\n        share one canonical target.\n        \"\"\"\n        server = urlparse(server_url)\n        request = urlparse(request_url)\n\n        if (request.scheme, request.username, request.password, request.hostname, request.port) != (\n            server.scheme,\n            server.username,\n            server.password,\n            server.hostname,\n            server.port,\n        ):\n            raise FunctionExecutionException(\n                f\"The operation path resolves to '{request.scheme}://{request.netloc}', which does not match \"\n                f\"the configured server '{server.scheme}://{server.netloc}'.\"\n            )\n\n        # get_server_url guarantees a trailing slash, so the server base path always ends with \"/\".\n        base_path = server.path\n        if request.path != base_path.rstrip(\"/\") and not request.path.startswith(base_path):\n            raise FunctionExecutionException(\n                f\"The operation path resolves to '{request.path}', which is outside the configured server \"\n                f\"base path '{base_path}'.\"\n            )\n\n    def get_server_url(self, server_url_override=None, api_host_url=None, arguments=None):\n        \"\"\"Get the server URL for the operation.\"\"\"\n        if arguments is None:\n            arguments = {}\n\n        # Prioritize server_url_override","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/openapi_plugin/models/rest_api_operation.py#L236-L272","documentation":"A security-oriented check: after joining the server URL and operation path, `_ensure_request_target_matches_server` verifies the resulting request URL has the same scheme, host, and port as the configured server. If they differ, this FunctionExecutionException is raised. This prevents an operation path or server-variable substitution from silently redirecting a credential-bearing request to an unintended host (SSRF protection).","triggerScenarios":"The operation path (after variable substitution and argument interpolation) resolves to a different scheme, host, or port than the configured server URL. For example a server variable substitution injects a different hostname, or the path contains an absolute URL.","commonSituations":"An OpenAPI spec path contains an absolute URL that overrides the server. A server URL variable is substituted with a value pointing to a different host. Malicious or malformed server-variable arguments. This guard complements the dot-segment and path-traversal checks.","solutions":["Ensure the operation path is relative and does not change the host/scheme/port of the configured server.","Verify server variable argument values point to the same host as the base server URL.","Correct the OpenAPI spec if a path legitimately needs to target a different server (use a separate server entry)."],"exampleFix":"// before (server variable redirects to different host)\nawait api.call_op(server_variables={\"host\": \"evil.example.com\"})\n// after\nawait api.call_op(server_variables={\"host\": \"api.example.com\"})","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\ndef validate_server_match(server_url: str, request_url: str):\n    s, r = urlparse(server_url), urlparse(request_url)\n    if (r.scheme, r.hostname, r.port) != (s.scheme, s.hostname, s.port):\n        raise ValueError(f\"Request target {r.scheme}://{r.netloc} does not match server {s.scheme}://{s.netloc}\")","typeGuard":null,"tryCatchPattern":"try:\n    result = await api.my_operation(**args)\nexcept FunctionExecutionException as e:\n    if \"does not match the configured server\" in str(e):\n        # ensure server variable values keep the same host/scheme/port\n        ...","preventionTips":["Ensure server variable substitutions keep the same scheme, host, and port as the base server.","Never allow user input to set server variables to arbitrary hosts.","Use server_url_override with a fixed, trusted URL when possible."],"tags":["openapi","rest-api","security","ssrf","url","semantic-kernel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}