They are stable, localized, and intentionally explicit so the frontend can react without guessing or parsing messages. Every error response is produced either by:
- global exception handling (
bootstrap/app.php) - domain controllers (auth, 2FA, registration, etc.)
Error contract (guaranteed)
Every error response follows one of the formats below.Standard error shape
codeStable, machine-readable identifier. Never localized. Never changes.messageHuman-readable explanation, always localized.- HTTP status Meaningful and intentional (see mapping below).
Validation error (HTTP 422)
Used exclusively for request validation failures.errorsis a field → array of messages map- messages are localized
- field names are never localized
- structure is stable across all endpoints
Localization of errors
Errors use the same locale resolution middleware as the rest of the API. Resolution order:X-App-Localeheader (recommended)Accept-Languageuser.locale(authenticated requests)- fallback:
fr
message- validation messages inside
errors - emails triggered during the request
code values are never localized and must always be used for logic.
HTTP status semantics (contract)
This mapping is intentional and consistent across the platform.
Global errors (from exception handling)
These errors can occur on any endpoint.Validation failed
HTTP:422
Code: VALIDATION_FAILED
- Render field-level errors next to inputs
- Do not show multiple global toasts
- Do not retry automatically
Unauthenticated
HTTP:401
Code: UNAUTHENTICATED
- Clear stored token
- Reset user state
- Redirect to login or onboarding entry point
Rate limited
HTTP:429
Code: RATE_LIMITED
- Disable the triggering action
- Show cooldown or timer
- Never retry automatically in a loop
Server error (production)
HTTP:500
Code: SERVER_ERROR
- Show generic error UI
- Offer a retry action
- Log client-side context if available
Authentication errors (anti-enumeration)
Authentication endpoints are deliberately strict.Invalid credentials
Returned for all of the following cases:- unknown email
- wrong password
- account not in
activestate
401
Code: INVALID_CREDENTIALS
- Never indicate which field failed
- Never suggest account existence
- Optional UX: show “Forgot password?” only if implemented
MFA (2FA) related errors
These errors occur during login or 2FA management.
Frontend guidance:
- Restart login on
MFA_CHALLENGE_GONE - Do not retry automatically
- Lock UI on
MFA_TOO_MANY_ATTEMPTS
Registration & onboarding errors
Frontend guidance:
- Always propose the next valid step
- Never reveal internal state
- Restart flows cleanly when needed
Frontend best practices (mandatory)
- Always branch logic on
code, never onmessage - Treat
429as a product constraint, not a bug - Never expose backend internals to users
- Never infer account existence from errors
- Assume all messages are localized
Guarantees
Flowxi error handling guarantees:- stable and documented error codes
- deterministic HTTP statuses
- strict anti-enumeration
- full localization coverage
- production-safe responses only
Testing checklist
- Verify identical responses for wrong email vs wrong password
- Trigger validation errors and inspect
errorsstructure - Hit rate limits and ensure UI cooldown
- Test expired MFA challenges
- Switch
X-App-Localeand verify translated messages

