BerriAI/litellm · error · ProxyException
f"Authentication Error({e})"
Error message
f"Authentication Error({e})" What it means
/user/update wraps every failure into a ProxyException with type auth_error. For HTTPExceptions it copies e.detail as the message; the literal 'Authentication Error({e})' text only appears through the getattr(e, 'detail', ...) fallback when the exception carries no detail attribute - rare, e.g. a malformed or bare HTTPException raised deep inside helpers. The response code is the original status_code when present, else 400.
Source
Thrown at litellm/proxy/management_endpoints/internal_user_endpoints.py:1590
- key_alias: Optional[str] - [NOT IMPLEMENTED].
- object_permission: Optional[LiteLLM_ObjectPermissionBase] - internal user-specific object permission. Example - {"vector_stores": ["vector_store_1"], "mcp_servers": ["github"], "mcp_tool_permissions": {"github": ["list_issues"]}}. The MCP grants act as a ceiling on every key this user holds. IF null or {} then no object permission.
- prompts: Optional[List[str]] - List of allowed prompts for the user. If specified, the user will only be able to use these specific prompts.
- budget_limits: Optional[list] - List of concurrent budget windows for the user. Each window specifies a budget_limit, time_period, and optional budget_duration. Example - [{"budget_limit": 10.0, "time_period": "1d"}, {"budget_limit": 50.0, "time_period": "7d"}].
"""
try:
verbose_proxy_logger.debug("/user/update: Received data = %s", data)
response: Final = await _update_single_user_helper(
user_request=data,
user_api_key_dict=user_api_key_dict,
)
return response
except Exception as e:
verbose_proxy_logger.exception("litellm.proxy.proxy_server.user_update(): Exception occured - %s", e)
verbose_proxy_logger.debug(traceback.format_exc())
if isinstance(e, HTTPException):
raise ProxyException(
message=getattr(e, "detail", f"Authentication Error({e})"),
type=ProxyErrorTypes.auth_error,
param=getattr(e, "param", "None"),
code=getattr(e, "status_code", status.HTTP_400_BAD_REQUEST),
)
elif isinstance(e, ProxyException):
raise e
raise ProxyException(
message="Authentication Error, " + str(e),
type=ProxyErrorTypes.auth_error,
param=getattr(e, "param", "None"),
code=status.HTTP_400_BAD_REQUEST,
)
async def bulk_update_processed_users(
users_to_update: list[UpdateUserRequest],
user_api_key_dict: UserAPIKeyAuth,View on GitHub (pinned to 77b7c6c40c)
Solutions
- Read the server logs first - the handler logs 'user_update(): Exception occured' plus the full traceback before wrapping
- Fix the underlying exception; in practice it is almost always one of the specific 4xx errors from this file (missing id, permissions, DB)
- Upgrade LiteLLM if the traceback shows a library-internal raise site
Defensive patterns
Strategy: try-catch
Try / catch
except requests.HTTPError as e:
body = e.response.json() if e.response is not None else {}
err = body.get("error", {}) if isinstance(body.get("error"), dict) else {}
if err.get("type") == "auth_error" and str(err.get("message", "")).startswith("Authentication Error"):
# generic wrapper: the real cause is in server logs; do not treat as an auth problem
... Prevention
- Correlate client-side 400s with proxy exception logs using timestamps
- Do not build logic on the 'Authentication Error' prefix - it wraps many non-auth failures
- Pin LiteLLM versions in CI so new raise sites do not surprise you
When it happens
Trigger: Any exception without a .detail attribute escaping the update pipeline during POST /user/update - a bare HTTPException(), a library-internal raise site, or custom exception types raised by hooks/helpers.
Common situations: Version drift where a helper raises a non-standard exception; seeing a generic auth message that actually masks a validation or database problem; debugging from the wrapped message instead of server logs.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- "Authentication Error, " + str(e)
- Not connected to DB!
- User={valid_token.user_id} has been deactivated via SCIM. Ke
- Error updating key: {response_text}
- License is over limit. Please contact support@berri.ai to up
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/4c9de4f82ecc17f8.
Report an issue: GitHub.