BerriAI/litellm · error · ValueError
Either user_id or user_email must be provided
Error message
Either user_id or user_email must be provided
What it means
UpdateUserRequest has optional user_id and user_email, but _update_single_user_helper requires at least one to identify the target; otherwise it raises ValueError 'Either user_id or user_email must be provided'. Because it is a ValueError (not HTTPException), /user/update converts it into a ProxyException 'Authentication Error, Either user_id or user_email must be provided' with code 400 - the auth prefix is cosmetic.
Source
Thrown at litellm/proxy/management_endpoints/internal_user_endpoints.py:1358
async def _update_single_user_helper(
user_request: UpdateUserRequest,
user_api_key_dict: UserAPIKeyAuth,
litellm_changed_by: str | None = None,
) -> dict[str, Any]:
"""
Helper function to update a single user.
Used by both user_update and bulk_user_update endpoints.
Returns the updated user data or raises an exception on failure.
"""
from litellm.proxy.proxy_server import litellm_proxy_admin_name, prisma_client
if prisma_client is None:
raise Exception("Not connected to DB!")
if not user_request.user_id and not user_request.user_email:
raise ValueError("Either user_id or user_email must be provided")
_check_permissions_caller_permission(
data=user_request,
user_api_key_dict=user_api_key_dict,
)
data_json: Final[dict] = user_request.model_dump(exclude_unset=True)
non_default_values = _update_internal_user_params(data_json=data_json, data=user_request)
_hash_password_in_dict(non_default_values)
existing_user_row: BaseModel | None = None
if user_request.user_id:
existing_user_row = await _user_table(prisma_client).find_first(where={"user_id": user_request.user_id})
elif user_request.user_email:
existing_user_row = await _user_table(prisma_client).find_first(where={"user_email": user_request.user_email})
_check_user_update_authz(user_request, user_api_key_dict, existing_user_row)
View on GitHub (pinned to 77b7c6c40c)
Solutions
- Include user_id (or user_email) of the target user in the body
- For self-update, still pass your own user_id explicitly - there is no implicit self-targeting
- Validate the payload client-side before sending the request
Example fix
# before
POST /user/update {"user_alias": "Krrish"} # 400 Authentication Error, Either user_id or user_email must be provided
# after
POST /user/update {"user_id": "krrish7@berri.ai", "user_alias": "Krrish"} # 200 Defensive patterns
Strategy: validation
Validate before calling
def validate_update_payload(payload: dict) -> dict:
if not payload.get("user_id") and not payload.get("user_email"):
raise ValueError("UpdateUserRequest needs user_id or user_email")
return payload Type guard
interface UpdateUserRequest { user_id?: string; user_email?: string; [k: string]: unknown }
function hasUserIdentifiers(p: UpdateUserRequest): boolean {
return (typeof p.user_id === "string" && p.user_id.length > 0)
|| (typeof p.user_email === "string" && p.user_email.length > 0);
} Try / catch
except requests.HTTPError as e:
body = e.response.text if e.response is not None else ""
if e.response is not None and e.response.status_code == 400 and "user_id or user_email" in body:
raise ValueError("payload must include user_id or user_email") from e
raise Prevention
- Make user_id required in your client models for update calls
- Build update payloads from a stored user object so an identifier is always present
- Unit-test payload builders for the identifier-missing case
When it happens
Trigger: POST /user/update with a body that contains neither user_id nor user_email - e.g. only user_alias or max_budget; dynamically built payloads where both identifiers were skipped.
Common situations: Client code assuming /user/update with no id targets the caller (it does not); forms that make both identifier fields optional; partial payloads after refactors.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- user_id is required. Either pass it as a query parameter or
- max_budget cannot be negative. Received: {data.max_budget}
- soft_budget cannot be negative. Received: {data.soft_budget}
- soft_budget ({data.soft_budget}) must be strictly lower than
- Model '{m}' not in team's allowed models. Team allowed model
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/d5566c54e8b50bae.
Report an issue: GitHub.