{"record":{"id":"d2c102ac3c19538d","repo":"BerriAI/litellm","slug":"tried-to-access-route-route-which-is-only-for-m","errorCode":null,"errorMessage":"Tried to access route={route}, which is only for MASTER KEY","messagePattern":"Tried to access route=(.+?), which is only for MASTER KEY","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/proxy/auth/user_api_key_auth.py","lineNumber":1707,"sourceCode":"                _cache_key_object(\n                    hashed_token=hash_token(master_key),\n                    user_api_key_obj=_user_api_key_obj,\n                    user_api_key_cache=user_api_key_cache,\n                    proxy_logging_obj=proxy_logging_obj,\n                )\n            )\n\n            _user_api_key_obj = update_valid_token_with_end_user_params(\n                valid_token=_user_api_key_obj, end_user_params=end_user_params\n            )\n            _user_api_key_obj.via_virtual_key = True\n\n            return _user_api_key_obj\n\n        ## IF it's not a master key\n        ## Route should not be in master_key_only_routes\n        if route in LiteLLMRoutes.master_key_only_routes.value:\n            raise Exception(f\"Tried to access route={route}, which is only for MASTER KEY\")\n\n        ## Check DB\n\n        if (\n            prisma_client is None\n        ):  # if both master key + user key submitted, and user key != master key, and no db connected, raise an error\n            raise ProxyException(\n                message=\"No connected db.\",\n                type=ProxyErrorTypes.no_db_connection,\n                code=400,\n                param=None,\n            )\n\n        if valid_token is None:\n            if isinstance(api_key, str):  # if generated token, make sure it starts with sk-.\n                _masked_key: Final = f\"{api_key[:4]}****{api_key[-4:]}\" if len(api_key) > 8 else \"****\"\n                if not api_key.startswith(\"sk-\"):\n                    _hint = _JWT_AUTH_DISABLED_HINT if not enable_jwt_auth and JWTHandler.is_jwt(token=api_key) else \"\"","sourceCodeStart":1689,"sourceCodeEnd":1725,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/user_api_key_auth.py#L1689-L1725","documentation":"Some proxy routes are reserved for the master key alone (listed in `LiteLLMRoutes.master_key_only_routes`). When the presented key is NOT the master key and the requested route is on that list, auth aborts with this exception before any handler logic runs — regardless of the caller's other permissions.","triggerScenarios":"Calling an admin-only route such as key/team/global management endpoints with a virtual key or team key instead of `LITELLM_MASTER_KEY`; e.g. `POST /key/generate` or router-level admin routes with a normal user's `sk-` key.","commonSituations":"Automation scripts provisioned with a virtual key that later need master-only operations; org admin assuming their admin role key suffices (role != master key); a config adding routes to `master_key_only_routes` that a service account's workflow depends on.","solutions":["Authenticate that request with the master key (`Authorization: Bearer <LITELLM_MASTER_KEY>`)","If the restriction is unwanted, edit `general_settings.master_key_only_routes` in config to remove the route (accepting the security tradeoff)","Split workflows: service accounts use virtual keys for inference, a secrets-managed master key for admin operations"],"exampleFix":"# before\nclient = OpenAI(base_url=..., api_key=user_virtual_key)\nclient.post(\"/key/generate\", json={...})  # -> only for MASTER KEY\n\n# after (dedicated admin client from secret store)\nadmin = OpenAI(base_url=..., api_key=os.environ[\"LITELLM_MASTER_KEY\"])\nadmin.post(\"/key/generate\", json={...})","handlingStrategy":"validation","validationCode":"MASTER_KEY_ONLY = {\"/key/generate\", \"/key/delete\", \"/global/spend/report\"}  # mirror your config list\nkey = MASTER_KEY if route in MASTER_KEY_ONLY else service_key\nheaders = {\"Authorization\": f\"Bearer {key}\"}","typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.post(f\"{PROXY}{route}\", headers=headers)\nexcept Exception as e:\n    if \"only for MASTER KEY\" in str(e):\n        raise PermissionError(f\"{route} requires the master key; rerun with elevated credential\") from e\n    raise","preventionTips":["Keep two clients: inference client on virtual keys, admin client on the master key from a secret store","Encode the master-key-only route list in a shared constant used by all automation","Review master_key_only_routes after proxy upgrades — the list can change"],"tags":["auth","master-key","permissions","admin-routes","litellm"],"backgroundTag":"insufficient-privileges","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}