{"record":{"id":"1136162adf7d98bb","repo":"BerriAI/litellm","slug":"advisor-tool-definition-sets-api-base-api-base","errorCode":null,"errorMessage":"advisor tool definition sets 'api_base'={api_base!r}, which must use the https scheme.","messagePattern":"advisor tool definition sets 'api_base'=(.+?), which must use the https scheme\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py","lineNumber":221,"sourceCode":"    and relies on certificate validation to block DNS rebinding, so this\n    closes the same gap without threading the pinned URL through the whole\n    ``anthropic_messages()`` call chain.\n    \"\"\"\n    if not _allow_client_side_advisor_credentials():\n        return None, None\n    api_key: Final[str | None] = advisor_tool.get(\"api_key\")\n    api_base: Final[str | None] = advisor_tool.get(\"api_base\")\n    if api_base is None:\n        return api_key, None\n    if not api_key:\n        raise ValueError(\n            \"advisor tool definition sets 'api_base' without 'api_key'. A \"\n            \"caller-supplied api_base is only honored alongside a \"\n            \"caller-supplied api_key, so the proxy's own credentials are \"\n            \"never sent to a caller-chosen destination.\"\n        )\n    if not api_base.startswith(\"https://\"):\n        raise ValueError(f\"advisor tool definition sets 'api_base'={api_base!r}, which must use the https scheme.\")\n    if getattr(litellm, \"ssl_verify\", True) is False:\n        raise ValueError(\n            \"advisor tool definition sets 'api_base' but the proxy has TLS verification \"\n            \"disabled (litellm.ssl_verify=False), so a caller-supplied api_base can't be \"\n            \"safely validated against DNS rebinding.\"\n        )\n    if getattr(litellm, \"user_url_validation\", True):\n        validate_url(api_base)\n    return api_key, api_base\n\n\ndef _make_synthetic_advisor_tool() -> dict:\n    \"\"\"Build a regular tool definition the executor provider can understand.\"\"\"\n    return {\n        \"name\": \"advisor\",\n        \"description\": ADVISOR_TOOL_DESCRIPTION,\n        \"input_schema\": {\n            \"type\": \"object\",","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py#L203-L239","documentation":"Follow-on guard in the advisor credential resolver: when a caller-supplied api_base is honored (api_key also present), the URL must use the https scheme. Plain http:// would transmit the caller's api_key in cleartext, so non-https bases are rejected before validate_url runs.","triggerScenarios":"Advisor tool with api_base='http://localhost:8000' (or any http:// URL) plus an api_key. The startswith('https://') check fails and raises with the offending URL embedded in the message.","commonSituations":"Pointing the advisor at a local dev server (vLLM/ollama-style endpoints are usually http://); internal HTTP-only services behind no TLS; typos like 'https:/example.com' (single slash) which fail the prefix check.","solutions":["Serve the destination over HTTPS and use an https:// URL, e.g. via a local reverse proxy with a self-signed or real cert (TLS verification must also be on).","For trusted internal destinations, register them as server-side models in the proxy config instead of client-side api_base.","Double-check the URL string: exactly 'https://' prefix, two slashes."],"exampleFix":"# before\ntools = [{\"type\": \"advisor\", \"model\": \"m\", \"api_key\": \"k\", \"api_base\": \"http://localhost:8000\"}]\n\n# after\ntools = [{\"type\": \"advisor\", \"model\": \"m\", \"api_key\": \"k\", \"api_base\": \"https://localhost:8443\"}]","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef validate_advisor_api_base(api_base: str) -> None:\n    if not api_base.startswith(\"https://\"):\n        raise ValueError(\"advisor api_base must use the https scheme\")\n    parsed = urlparse(api_base)\n    if not parsed.netloc:\n        raise ValueError(\"advisor api_base must be a valid https URL\")","typeGuard":"def is_https_url(url: object) -> bool:\n    return isinstance(url, str) and url.startswith(\"https://\") and bool(urlparse(url).netloc)","tryCatchPattern":"try:\n    resp = litellm.anthropic_messages(tools=tools, ...)\nexcept ValueError as e:\n    if \"must use the https scheme\" in str(e):\n        return http_error(400, \"advisor api_base must be https\")\n    raise","preventionTips":["Run local advisors behind an HTTPS reverse proxy (caddy/nginx with any trusted cert).","Validate advisor URLs in config loading, not only at request time.","Remember localhost http:// is rejected exactly like remote http://."],"tags":["anthropic","advisor","security","tls","url-validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}