{"record":{"id":"a97bacc80e54a340","repo":"iflytek/astron-agent","slug":"errcode-server-validate-err","errorCode":"ErrCode.SERVER_VALIDATE_ERR","errorMessage":"<dynamic outbound policy violation: str(exc)>","messagePattern":"<dynamic outbound policy violation: str\\(exc\\)>","errorType":"error_code","errorClass":"CallThirdApiException","httpStatus":null,"severity":"error","filePath":"core/plugin/link/infra/tool_exector/process.py","lineNumber":101,"sourceCode":"            self._is_auth_hmac = False\n            self.auth_con_js = object\n        try:\n            self._is_official = HttpRun.is_official(open_api_schema)\n        except Exception:\n            self._is_official = False\n        # Invalid security configuration must fail closed instead of silently disabling checks.\n        self._outbound_policy = OutboundPolicy.from_environment()\n\n    def _validate_destination(self, url: str) -> None:\n        \"\"\"Validate the final URL before constructing an outbound connection.\n\n        Raises:\n            CallThirdApiException: When the destination violates egress policy\n        \"\"\"\n        try:\n            self._outbound_policy.validate_url(url)\n        except OutboundPolicyError as exc:\n            raise CallThirdApiException(\n                code=ErrCode.SERVER_VALIDATE_ERR.code,\n                err_pre=ErrCode.SERVER_VALIDATE_ERR.msg,\n                err=str(exc),\n            ) from exc\n\n    def _build_url(self) -> str:\n        \"\"\"Build request URL with authentication and query parameters.\n\n        Returns:\n            str: Complete URL for the request\n        \"\"\"\n        url = self.server\n\n        # Substitute OpenAPI path parameters as individual path segments. urljoin is unsafe here:\n        # an absolute value, a scheme-relative value, or a dot segment can replace/escape the\n        # persisted endpoint path.\n        for name, value in self.path.items():\n            placeholder = \"{\" + str(name) + \"}\"","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/link/infra/tool_exector/process.py#L83-L119","documentation":"_validate_destination runs the fully-built request URL through the OutboundPolicy (SSRF guard) before any connection is made. If the policy rejects the URL (malformed URL, non-HTTP scheme, blocked domain, blocked/unsafe IP, embedded userinfo, etc.), the OutboundPolicyError is wrapped in CallThirdApiException with code ErrCode.SERVER_VALIDATE_ERR and the policy message as err. This is the egress-security check that fails the tool call closed.","triggerScenarios":"Calling HttpRun.do_call (via _execute_request) where the final URL violates outbound policy: e.g. DOMAIN_BLACK_LIST match, IP segment/IP blacklist match, non-http(s) scheme, missing hostname, username/password in URL, fragment present, invalid port, or control characters.","commonSituations":"Tool registered against a hostname that ops has blacklisted; tool server uses an internal/private IP that is not on PRIVATE_ENDPOINT_ALLOW_LIST; URL contains 'user:pass@host' credentials; port typo like :99999.","solutions":["Read the err field for the underlying OutboundPolicyError message to see which rule fired","If the destination is legitimately required, update the link-service env config: remove it from DOMAIN_BLACK_LIST/SEGMENT_BLACK_LIST/IP_BLACK_LIST or add it to PRIVATE_ENDPOINT_ALLOW_LIST / IP_WHITE_LIST as appropriate","Fix the tool endpoint configuration (scheme, port, remove embedded credentials) so the URL passes the policy"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"from urllib.parse import urlsplit\ndef passes_basic_policy(url, blocked_domains):\n    p = urlsplit(url)\n    host = (p.hostname or \"\").lower().rstrip(\".\")\n    return p.scheme in (\"http\", \"https\") and not any(host == d or host.endswith('.' + d) for d in blocked_domains) and p.username is None and not p.fragment","typeGuard":null,"tryCatchPattern":"try:\n    result = await run.do_call(span)\nexcept CallThirdApiException as e:\n    if e.code == ErrCode.SERVER_VALIDATE_ERR.code:\n        audit.log('egress blocked', url, e.err)\n        raise PolicyViolation(e.err) from e\n    raise","preventionTips":["Keep tool destinations on an allow-list reviewed by security","Never embed user:pass credentials in tool URLs","Coordinate with ops before adding domains to the blacklist"],"tags":["security","ssrf","http"],"backgroundTag":"invalid-url","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}