fix(auth): localize login error message for failed credentials#2890
fix(auth): localize login error message for failed credentials#2890lawrence3699 wants to merge 1 commit intoChainlit:mainfrom
Conversation
The backend was sending `detail="credentialssignin"` (all lowercase) but every translation file defines the key as `credentialsSignin` (camelCase). The frontend also applied `.toLowerCase()` before the i18n lookup, guaranteeing the mismatch. On top of that, the global API error handler was toasting the raw error string for 401 responses, so users saw `(!) : credentialssignin` instead of the translated "Sign in failed. Check the details you provided are correct". Three changes fix this: 1. Backend: send `credentialsSignin` to match translation keys 2. LoginForm: drop `.toLowerCase()` so the camelCase key survives 3. API client: skip `toast.error` for 401s — they're already handled by the login form (inline Alert) and the `on401` redirect Fixes Chainlit#2873 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes the login “wrong credentials” error localization by aligning the backend error detail value and frontend i18n lookup behavior, and by preventing a redundant global toast on 401s.
Changes:
- Backend now returns
detail="credentialsSignin"(camelCase) for failed password auth to match translation keys. - Login form no longer lowercases the error key before translation lookup.
- Global API error handler skips
toast.errorfor 401 responses; Cypress assertion updated for the translated message.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| backend/chainlit/server.py | Aligns 401 login failure detail with existing translation keys (credentialsSignin). |
| frontend/src/components/LoginForm.tsx | Preserves error key casing so t() can resolve auth.login.errors.* entries correctly. |
| frontend/src/api/index.ts | Avoids showing a global toast for 401s (login page handles inline; other pages redirect). |
| cypress/e2e/password_auth/spec.cy.ts | Updates wrong-credentials expectation toward the translated copy (but should more directly assert “no toast + inline alert”). |
| cy.get("input[name='email']").type('user'); | ||
| cy.get("input[name='password']").type('user'); | ||
| cy.get("button[type='submit']").click(); | ||
| cy.get('body').should('contain', 'Unauthorized'); | ||
| cy.get('body').should('contain', 'Sign in failed'); | ||
| }); |
There was a problem hiding this comment.
The assertion cy.get('body').should('contain', 'Sign in failed') doesn’t verify the behavior this PR is aiming for (inline Alert is shown and no toast is displayed). Consider asserting on the inline alert element (e.g., .alert) for the translated text, and separately asserting that the toast container (App renders a Toaster with className="toast") does not contain the error / has no toast items, so the test will fail if the global toast reappears.
Summary
Fixes #2873 — follow-up to #2794.
After #2794 fixed the login form to read
err.detailinstead oferr.message, there's still a case sensitivity mismatch that prevents the i18n lookup from working. Users see a raw toast(!) Unauthorized: credentialssignininstead of the translated "Sign in failed. Check the details you provided are correct".Root cause
Three things conspire:
detail="credentialssignin"(all lowercase), but every translation file defines the key ascredentialsSignin(camelCase)LoginForm.tsxapplies.toLowerCase()before the i18n lookup, so even a correctly-cased key gets lowercasedonErrorhandler inapi/index.tstoastserror.toString()for every API error — including 401s on the login page, which theLoginFormalready handles with an inline AlertChanges
backend/chainlit/server.py— sendcredentialsSignin(camelCase) to match the translation keys in all 23 locale filesfrontend/src/components/LoginForm.tsx— remove.toLowerCase()so the key survives to match the translationfrontend/src/api/index.ts— skiptoast.errorfor 401 responses; they're already handled by the login form's inline Alert and theon401redirect for other pagescypress/e2e/password_auth/spec.cy.ts— update the wrong-credentials assertion to check for the translated message ("Sign in failed") instead of the old raw toast text ("Unauthorized")Before / After
(!) Unauthorized: credentialssigninChecks run
uv run pytest tests/— 783 passedpnpm test(frontend) — 32 passedpnpm lint— cleanpnpm format-check— cleanSummary by cubic
Fixes login error localization for failed credentials so users see the translated inline alert instead of a raw unauthorized toast. Removes the redundant 401 toast and aligns backend/Frontend keys for i18n.
credentialsSignin(camelCase) to match translation keys..toLowerCase()so the i18n key matches.toast.errorfor 401 responses; handled by inline Alert andon401.Written for commit 3568ccd. Summary will update on new commits.