{"record":{"id":"77c3d5986c808ffb","repo":"BerriAI/litellm","slug":"virtual-key-is-not-allowed-to-call-this-route-onl","errorCode":null,"errorMessage":"Virtual key is not allowed to call this route. Only allowed to call routes: {valid_token.allowed_routes}. Tried to call route: {route}","messagePattern":"Virtual key is not allowed to call this route\\. Only allowed to call routes: (.+?)\\. Tried to call route: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/auth/route_checks.py","lineNumber":176,"sourceCode":"                        # so virtual keys with allowed_routes=[\"llm_api_routes\"]\n                        # can list/inspect MCP servers. The GET handlers in\n                        # mcp_management_endpoints.py sanitize the response\n                        # for restricted virtual keys (stripping url,\n                        # headers, env, credentials). POST/PUT/DELETE on\n                        # these paths are admin-only management writes and\n                        # are intentionally not covered.\n                        if RouteChecks._is_get_mcp_server_discovery_route(route=route, request=request):\n                            return True\n\n        # check if wildcard pattern is allowed\n        for allowed_route in valid_token.allowed_routes:\n            if RouteChecks._route_matches_wildcard_pattern(route=route, pattern=allowed_route):\n                return True\n\n        if denied_auth_enforced_pass_through_route:\n            raise RouteChecks._auth_pass_through_denied_exception(route=route)\n\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=f\"Virtual key is not allowed to call this route. Only allowed to call routes: {valid_token.allowed_routes}. Tried to call route: {route}\",\n        )\n\n    @staticmethod\n    def _mask_user_id(user_id: str) -> str:\n        \"\"\"\n        Mask user_id to prevent leaking sensitive information in error messages\n\n        Args:\n            user_id (str): The user_id to mask\n\n        Returns:\n            str: Masked user_id showing only first 2 and last 2 characters\n        \"\"\"\n        from litellm.litellm_core_utils.sensitive_data_masker import SensitiveDataMasker\n\n        if not user_id or len(user_id) <= 4:","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/route_checks.py#L158-L194","documentation":"Raised in RouteChecks when a virtual key carries an allowed_routes restriction and the incoming request's route is not in that list (after the documented carve-outs, e.g. read-only MCP discovery GETs, are applied). Both the key's allowed routes and the attempted route are embedded; the fix is on the proxy-admin side — extend allowed_routes for that key.","triggerScenarios":"Thrown at litellm/proxy/auth/route_checks.py:176 when the library encounters an invalid state.","commonSituations":"The virtual key's allowed_routes does not include the requested route.","solutions":["Call one of the routes listed in the key's allowed_routes.","Update the key via /key/update to include the route you need."],"exampleFix":"curl -X POST $PROXY/key/update -d '{\"key\": \"sk-...\", \"allowed_routes\": [\"/chat/completions\"]}'","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}