iflytek/astron-agent · error · OutboundPolicyError

Tool path parameter has no matching placeholder

Error message

Tool path parameter has no matching placeholder: {name}

What it means

When substituting OpenAPI path parameters into the endpoint URL, each configured path variable must match a {placeholder} in the server URL. If a parameter named in the tool's path map has no corresponding {name} placeholder in the URL, the library raises OutboundPolicyError rather than silently dropping or appending the parameter. This is fail-closed behavior preventing parameters from being misplaced or injected elsewhere in the URL.

Solutions

  1. Compare the parameter name in the message against the {placeholders} in the tool's server URL and make them match exactly
  2. Update the tool's OpenAPI schema so the endpoint template includes the required placeholder, e.g. https://api.example.com/pets/{petId}
  3. Remove the extraneous path parameter from the request if it is not part of the endpoint

Example fix

// before
path = {"petId": 42}  # server = "https://api.example.com/pets"
// after
path = {"petId": 42}  # server = "https://api.example.com/pets/{petId}"
Defensive patterns

Strategy: validation

Validate before calling

import re
def path_params_match(template, params):
    placeholders = set(re.findall(r"\{([^{}]+)\}", template))
    return all(("{" + k + "}") in placeholders for k in params)

Try / catch

try:
    result = await run.do_call(span)
except CallThirdApiException as e:
    if 'no matching placeholder' in str(e.err):
        fix_tool_schema_or_params(e.err)
    raise

Prevention

When it happens

Trigger: do_call → _build_url where self.path contains a key (e.g. 'petId') but the server URL has no '{petId}' placeholder — typically because the registered endpoint template lacks the placeholder or the parameter name differs in case/spelling.

Common situations: Tool OpenAPI schema edited so the endpoint template no longer contains the placeholder; client supplies extra path parameters not declared in the template; placeholder renamed (e.g. {pet_id} vs {petId}) in schema or caller.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/72c6aa5222d64350. Report an issue: GitHub.

Appendix: source

Thrown at core/plugin/link/infra/tool_exector/process.py:121

                err_pre=ErrCode.SERVER_VALIDATE_ERR.msg,
                err=str(exc),
            ) from exc

    def _build_url(self) -> str:
        """Build request URL with authentication and query parameters.

        Returns:
            str: Complete URL for the request
        """
        url = self.server

        # Substitute OpenAPI path parameters as individual path segments. urljoin is unsafe here:
        # an absolute value, a scheme-relative value, or a dot segment can replace/escape the
        # persisted endpoint path.
        for name, value in self.path.items():
            placeholder = "{" + str(name) + "}"
            if placeholder not in url:
                raise OutboundPolicyError(
                    f"Tool path parameter has no matching placeholder: {name}"
                )
            raw_value = str(value)
            if (
                raw_value in {".", ".."}
                or "/" in raw_value
                or "\\" in raw_value
                or any(ord(character) < 0x20 for character in raw_value)
            ):
                raise OutboundPolicyError("Tool path parameter is unsafe")
            url = url.replace(placeholder, quote(raw_value, safe=""))

        if _PATH_PARAMETER_PATTERN.search(url):
            raise OutboundPolicyError("Tool URL has unresolved path parameters")

        # Authentication method selection and URL construction
        if self._is_authorization_md5:
            url = public_query_url(url)

View on GitHub (pinned to 5e758547a8)