From 27c76c677aab6f0ec4fe27471d700f95f748e7a9 Mon Sep 17 00:00:00 2001 From: Patrick Monteith Date: Thu, 19 Feb 2026 21:08:42 +0000 Subject: [PATCH] fix: clamp SCIM pagination args instead of rejecting them (#21577) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC 7644 §3.4.2.4 specifies that out-of-range pagination values MUST be clamped, not rejected. The previous implementation used FastAPI Query constraints (ge=1, le=100) which caused a 422 response for values like startIndex=0 or count=9999 — violating the spec. For both /Users and /Groups: - startIndex < 1 is now treated as 1 (spec: "SHALL be interpreted as 1") - count < 0 is now treated as 0 (spec: "SHALL be interpreted as 0") - count > 100 is clamped to the server maximum of 100 Co-authored-by: Claude Sonnet 4.6 --- backend/open_webui/routers/scim.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/routers/scim.py b/backend/open_webui/routers/scim.py index 0c16eb99b..4d56a7e97 100644 --- a/backend/open_webui/routers/scim.py +++ b/backend/open_webui/routers/scim.py @@ -523,13 +523,17 @@ async def get_schemas(): @router.get("/Users", response_model=SCIMListResponse) async def get_users( request: Request, - startIndex: int = Query(1, ge=1), - count: int = Query(20, ge=1, le=100), + startIndex: int = Query(1), + count: int = Query(20), filter: Optional[str] = None, _: bool = Depends(get_scim_auth), db: Session = Depends(get_session), ): """List SCIM Users""" + # Clamp per SCIM 2.0 spec (RFC 7644 §3.4.2.4): + # startIndex < 1 SHALL be treated as 1; count < 0 SHALL be treated as 0. + startIndex = max(1, startIndex) + count = max(0, min(100, count)) skip = startIndex - 1 limit = count @@ -794,13 +798,18 @@ async def delete_user( @router.get("/Groups", response_model=SCIMListResponse) async def get_groups( request: Request, - startIndex: int = Query(1, ge=1), - count: int = Query(20, ge=1, le=100), + startIndex: int = Query(1), + count: int = Query(20), filter: Optional[str] = None, _: bool = Depends(get_scim_auth), db: Session = Depends(get_session), ): """List SCIM Groups""" + # Clamp per SCIM 2.0 spec (RFC 7644 §3.4.2.4): + # startIndex < 1 SHALL be treated as 1; count < 0 SHALL be treated as 0. + startIndex = max(1, startIndex) + count = max(0, min(100, count)) + # Get all groups groups_list = Groups.get_all_groups(db=db)