{"record":{"id":"d6cd1f2306e981c0","repo":"BerriAI/litellm","slug":"e-d6cd1f","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"exception","errorClass":"UnauthorizedError","httpStatus":401,"severity":"error","filePath":"litellm/proxy/client/models.py","lineNumber":63,"sourceCode":"        Raises:\n            UnauthorizedError: If the request fails with a 401 status code\n            requests.exceptions.RequestException: If the request fails with any other error\n        \"\"\"\n        url: Final = f\"{self._base_url}/models\"\n        request: Final = requests.Request(\"GET\", url, headers=self._get_headers())\n\n        if return_request:\n            return request\n\n        # Prepare and send the request\n        session: Final = requests.Session()\n        try:\n            response: Final = session.send(request.prepare())\n            response.raise_for_status()\n            return response.json()[\"data\"]\n        except requests.exceptions.HTTPError as e:\n            if e.response.status_code == 401:\n                raise UnauthorizedError(e)\n            raise\n\n    def new(\n        self,\n        model_name: str,\n        model_params: dict[str, Any],\n        model_info: dict[str, Any] | None = None,\n        return_request: bool = False,\n    ) -> dict[str, Any] | requests.Request:\n        \"\"\"\n        Add a new model to the proxy.\n\n        Args:\n            model_name (str): Name of the model to add\n            model_params (Dict[str, Any]): Parameters for the model (e.g., model type, api_base, api_key)\n            model_info (Optional[Dict[str, Any]]): Additional information about the model\n            return_request (bool): If True, returns the prepared request object instead of executing it\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/client/models.py#L45-L81","documentation":"Raised by ModelsManagementClient.list() when GET {base_url}/models returns HTTP 401, converted to UnauthorizedError (redacted message; original on .orig_exception; other non-2xx re-raise as plain requests HTTPError). /models is the OpenAI-style model list that many proxies leave public, so this 401 specifically means your proxy enforces auth on it (master key / strict auth configured) and the client's Bearer credentials were absent or rejected.","triggerScenarios":"Calling models.list() with api_key=None against a proxy configured with a master_key or otherwise requiring auth; a wrong/rotated key; a virtual key the proxy refuses for this route.","commonSituations":"Code written against an open dev proxy moved to a hardened prod proxy; env var with the key not set in the new deployment; key rotated during incident response.","solutions":["Pass a valid key: ModelsManagementClient(base_url, api_key=os.environ[\"LITELLM_MASTER_KEY\"]).list()","Confirm enforcement expectations: curl $BASE_URL/models (no auth) vs curl -H \"Authorization: Bearer $KEY\" $BASE_URL/models","Rotate/refresh the key if the proxy rejects it","Check base_url — a wrong port can hit a different service that answers 401"],"exampleFix":"# before\nfrom litellm.proxy.client.models import ModelsManagementClient\nmodels = ModelsManagementClient(\"http://localhost:4000\")\nmodels.list()  # UnauthorizedError\n\n# after\nimport os\nmodels = ModelsManagementClient(\"http://localhost:4000\", api_key=os.environ[\"LITELLM_MASTER_KEY\"])\nmodels.list()","handlingStrategy":"try-catch","validationCode":"import requests\n\ndef models_listable(base_url: str, api_key: str | None) -> bool:\n    r = requests.get(\n        f\"{base_url.rstrip('/')}/models\",\n        headers={\"Authorization\": f\"Bearer {api_key}\"} if api_key else {},\n        timeout=10,\n    )\n    return r.status_code != 401","typeGuard":null,"tryCatchPattern":"from litellm.proxy.client.exceptions import UnauthorizedError\nimport requests\n\ntry:\n    models = client.list()\nexcept UnauthorizedError:\n    raise RuntimeError(\"proxy requires auth for /models — supply a valid key\") from None\nexcept requests.exceptions.HTTPError as e:\n    handle(e.response)  # 5xx etc.","preventionTips":["Don't assume /models is public — pass the key even for model listing in prod","Smoke-test GET {base_url}/models with the intended credentials during deployment checks","Keep dev (open) and prod (authed) proxy configurations in sync to avoid surprise 401s"],"tags":["litellm","authentication","http-401","python","models"],"backgroundTag":"http-401-unauthorized","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}