From be585934b9363f8e255bc77ae02b4522737ab2fd Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:19:10 +0200 Subject: [PATCH] fix: show descriptive error when creating local user with OIDC enabled Return a JSON error body from UserAdminController instead of an empty 400, and extract API error messages in adminFetch so toasts display the reason. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../server/app/controller/UserAdminController.java | 5 +++-- ui/src/api/queries/admin/admin-api.ts | 12 +++++++++++- ui/src/pages/Admin/UsersTab.tsx | 5 +++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java index b31f8089..4ff56d27 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java @@ -87,10 +87,11 @@ public class UserAdminController { @Operation(summary = "Create a local user") @ApiResponse(responseCode = "200", description = "User created") @ApiResponse(responseCode = "400", description = "Disabled in OIDC mode") - public ResponseEntity createUser(@RequestBody CreateUserRequest request, + public ResponseEntity createUser(@RequestBody CreateUserRequest request, HttpServletRequest httpRequest) { if (oidcEnabled) { - return ResponseEntity.badRequest().build(); + return ResponseEntity.badRequest() + .body(Map.of("error", "Local user creation is disabled when OIDC is enabled. Users are provisioned automatically via SSO.")); } String userId = "user:" + request.username(); UserInfo user = new UserInfo(userId, "local", diff --git a/ui/src/api/queries/admin/admin-api.ts b/ui/src/api/queries/admin/admin-api.ts index be6cfb24..a92516b7 100644 --- a/ui/src/api/queries/admin/admin-api.ts +++ b/ui/src/api/queries/admin/admin-api.ts @@ -16,7 +16,17 @@ export async function adminFetch(path: string, options?: RequestInit): Promis useAuthStore.getState().logout(); throw new Error('Unauthorized'); } - if (!res.ok) throw new Error(`API error: ${res.status}`); + if (!res.ok) { + let message = `API error: ${res.status}`; + try { + const body = await res.json(); + if (body?.error) message = body.error; + else if (body?.message) message = body.message; + } catch { + // no JSON body — keep generic message + } + throw new Error(message); + } if (res.status === 204) return undefined as T; const text = await res.text(); if (!text) return undefined as T; diff --git a/ui/src/pages/Admin/UsersTab.tsx b/ui/src/pages/Admin/UsersTab.tsx index 4d3bafbe..7e7ec05f 100644 --- a/ui/src/pages/Admin/UsersTab.tsx +++ b/ui/src/pages/Admin/UsersTab.tsx @@ -145,8 +145,9 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig setNewPassword(''); setNewProvider('local'); }, - onError: () => { - toast({ title: 'Failed to create user', variant: 'error', duration: 86_400_000 }); + onError: (err: unknown) => { + const message = err instanceof Error ? err.message : 'Unknown error'; + toast({ title: 'Failed to create user', description: message, variant: 'error', duration: 86_400_000 }); }, }, );