{"record":{"id":"d5566c54e8b50bae","repo":"BerriAI/litellm","slug":"either-user-id-or-user-email-must-be-provided-d5566c","errorCode":null,"errorMessage":"Either user_id or user_email must be provided","messagePattern":"Either user_id or user_email must be provided","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/management_endpoints/internal_user_endpoints.py","lineNumber":1358,"sourceCode":"\nasync def _update_single_user_helper(\n    user_request: UpdateUserRequest,\n    user_api_key_dict: UserAPIKeyAuth,\n    litellm_changed_by: str | None = None,\n) -> dict[str, Any]:\n    \"\"\"\n    Helper function to update a single user.\n    Used by both user_update and bulk_user_update endpoints.\n\n    Returns the updated user data or raises an exception on failure.\n    \"\"\"\n    from litellm.proxy.proxy_server import litellm_proxy_admin_name, prisma_client\n\n    if prisma_client is None:\n        raise Exception(\"Not connected to DB!\")\n\n    if not user_request.user_id and not user_request.user_email:\n        raise ValueError(\"Either user_id or user_email must be provided\")\n\n    _check_permissions_caller_permission(\n        data=user_request,\n        user_api_key_dict=user_api_key_dict,\n    )\n\n    data_json: Final[dict] = user_request.model_dump(exclude_unset=True)\n    non_default_values = _update_internal_user_params(data_json=data_json, data=user_request)\n    _hash_password_in_dict(non_default_values)\n\n    existing_user_row: BaseModel | None = None\n    if user_request.user_id:\n        existing_user_row = await _user_table(prisma_client).find_first(where={\"user_id\": user_request.user_id})\n    elif user_request.user_email:\n        existing_user_row = await _user_table(prisma_client).find_first(where={\"user_email\": user_request.user_email})\n\n    _check_user_update_authz(user_request, user_api_key_dict, existing_user_row)\n","sourceCodeStart":1340,"sourceCodeEnd":1376,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/internal_user_endpoints.py#L1340-L1376","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nPOST /user/update {\"user_alias\": \"Krrish\"}   # 400 Authentication Error, Either user_id or user_email must be provided\n\n# after\nPOST /user/update {\"user_id\": \"krrish7@berri.ai\", \"user_alias\": \"Krrish\"}  # 200","handlingStrategy":"validation","validationCode":"def validate_update_payload(payload: dict) -> dict:\n    if not payload.get(\"user_id\") and not payload.get(\"user_email\"):\n        raise ValueError(\"UpdateUserRequest needs user_id or user_email\")\n    return payload","typeGuard":"interface UpdateUserRequest { user_id?: string; user_email?: string; [k: string]: unknown }\nfunction hasUserIdentifiers(p: UpdateUserRequest): boolean {\n  return (typeof p.user_id === \"string\" && p.user_id.length > 0)\n      || (typeof p.user_email === \"string\" && p.user_email.length > 0);\n}","tryCatchPattern":"except requests.HTTPError as e:\n    body = e.response.text if e.response is not None else \"\"\n    if e.response is not None and e.response.status_code == 400 and \"user_id or user_email\" in body:\n        raise ValueError(\"payload must include user_id or user_email\") from e\n    raise","preventionTips":["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"],"tags":["litellm","validation","user-management","missing-param"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T08:17:14.275Z"}