Skip to content

fix(identity): return 400 with specific reasons on registration failure#1307

Merged
iammukeshm merged 2 commits into
mainfrom
fix/registration-error-clarity
Jun 23, 2026
Merged

fix(identity): return 400 with specific reasons on registration failure#1307
iammukeshm merged 2 commits into
mainfrom
fix/registration-error-clarity

Conversation

@iammukeshm

Copy link
Copy Markdown
Member

Problem

Registering a user that already exists (or with a weak password) surfaced a misleading toast: 500 error while registering a new user — a scary server-error code with no indication of what to fix.

before

Root cause spans three layers:

  1. Wrong status (backend) — Identity create-user failures are thrown as CustomException, which defaults to HTTP 500. Duplicate email/username and password-policy violations are client-input errors → should be 400.
  2. Generic message (backend) — the specific reasons ("Email 'x' is already taken", "Passwords must have at least one digit") live in CustomException.ErrorMessages, which GlobalExceptionHandler already exposes in the ProblemDetails errors extension. They just never reached the top-level message.
  3. Clients drop errors[] — the dashboard describe() and the admin create-user onError only read detail/title/message, discarding the errors array, so the real reason never reached the toast.

Changes

BackendUserRegistrationService.cs

  • Registration failures and password-mismatch now throw with HttpStatusCode.BadRequest instead of the default 500.

Frontend — both apps now surface the ProblemDetails errors array:

  • dashboard lib/list-helpers.ts describe()
  • admin: new shared describeError() in lib/api-client.ts, wired into create-user-dialog.tsx
  • Both error shapes handled: Identity's flat string[] and FluentValidation's field-keyed map.

Tests — tightened the duplicate-email and weak-password registration integration tests to assert 400 BadRequest (previously only checked non-success).

Result

The toast now reads e.g. Email 'foo@bar.com' is already taken.

Verification

  • Full backend suite (dotnet test src/FSH.Starter.slnx): 0 failures (Integration 715, Identity 312, +others).
  • Both clients tsc -b clean; ESLint clean on changed files.

Docs

Per repo rule #10, this is a user-facing behavior change (registration now returns 400 + detailed reasons). A matching update to the docs repo may be warranted if it documents identity error responses.

🤖 Generated with Claude Code

iammukeshm and others added 2 commits June 23, 2026 05:00
Ran npm audit fix in clients/admin and clients/dashboard (all fixes
within existing semver ranges) plus an esbuild override:

- react-router 7.14.1 -> 7.18.0 (turbo-stream RCE, __manifest DoS, CSRF)
- vite 7.3.2 -> 7.3.5 (server.fs.deny bypass, launch-editor NTLMv2)
- ws 7.5.10 -> 7.5.11 (memory-exhaustion DoS)
- js-yaml 4.1.1 -> 4.2.0 (quadratic-complexity DoS)
- @babel/* -> 7.29.7 (sourceMappingURL arbitrary file read)
- esbuild -> 0.28.1 via overrides (dev-server file read); vite 7 pins
  ^0.27.0 and 0.28.1 is the only patched release, so an override avoids
  the breaking vite 8 / plugin-react 6 major bump

Both apps: npm audit reports 0 vulnerabilities and the production build
(tsc -b + vite build) passes clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Registration failures (duplicate email/username, weak password) were thrown
as CustomException defaulting to HTTP 500, and the actual Identity reasons —
already carried in ErrorMessages → ProblemDetails `errors` — were dropped by
the clients. Users saw a misleading "500 error while registering a new user"
with no indication of what to fix.

Backend: throw these (and password-mismatch) as 400 BadRequest, since they are
client-input errors, not server faults.

Frontend: surface the ProblemDetails `errors` array in both apps. dashboard's
describe() and a new shared admin describeError() now show the real reason
(e.g. "Email 'x' is already taken.") instead of the bare status + generic
detail. Both shapes handled (Identity flat string[]; FluentValidation map).

Tests: tighten the duplicate-email and weak-password registration integration
tests to assert 400 instead of just non-success.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@iammukeshm iammukeshm merged commit 5f2de95 into main Jun 23, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant