From 8462426be09f4de9d81ad8ec394ccf239b65c8ed Mon Sep 17 00:00:00 2001 From: theshivam7 Date: Tue, 7 Apr 2026 23:43:58 +0530 Subject: [PATCH] fix: make UserUpdateForm fields optional to allow partial user updates Fixes #23424 Previously, the PATCH /{user_id}/update endpoint required all fields (role, name, email, profile_image_url) even when only updating one. This caused a validation error when callers only passed a single field. Make all non-password fields Optional with None defaults. The router now only updates fields that are explicitly provided, leaving the rest unchanged. --- backend/open_webui/models/users.py | 12 +++++++----- backend/open_webui/routers/users.py | 23 +++++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index ef90745efe..d0a7e0aa5c 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -247,15 +247,17 @@ class UserRoleUpdateForm(BaseModel): class UserUpdateForm(BaseModel): - role: str - name: str - email: str - profile_image_url: str + role: Optional[str] = None + name: Optional[str] = None + email: Optional[str] = None + profile_image_url: Optional[str] = None password: Optional[str] = None @field_validator('profile_image_url') @classmethod - def check_profile_image_url(cls, v: str) -> str: + def check_profile_image_url(cls, v: Optional[str]) -> Optional[str]: + if v is None: + return v return validate_profile_image_url(v) diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 0ccc20185e..1d47b31c98 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -573,7 +573,7 @@ async def update_user_by_id( detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) - if form_data.role != 'admin': + if form_data.role is not None and form_data.role != 'admin': # If the primary admin is trying to change their own role, prevent it raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -590,7 +590,7 @@ async def update_user_by_id( user = Users.get_user_by_id(user_id, db=db) if user: - if form_data.email.lower() != user.email: + if form_data.email is not None and form_data.email.lower() != user.email: email_user = Users.get_user_by_email(form_data.email.lower(), db=db) if email_user: raise HTTPException( @@ -607,15 +607,22 @@ async def update_user_by_id( hashed = get_password_hash(form_data.password) Auths.update_user_password_by_id(user_id, hashed, db=db) - Auths.update_email_by_id(user_id, form_data.email.lower(), db=db) - updated_user = Users.update_user_by_id( - user_id, - { + if form_data.email is not None: + Auths.update_email_by_id(user_id, form_data.email.lower(), db=db) + + update_data = { + k: v + for k, v in { 'role': form_data.role, 'name': form_data.name, - 'email': form_data.email.lower(), + 'email': form_data.email.lower() if form_data.email is not None else None, 'profile_image_url': form_data.profile_image_url, - }, + }.items() + if v is not None + } + updated_user = Users.update_user_by_id( + user_id, + update_data, db=db, )