Error Handling & Callbacks
Relevant source files
The following files were used as context for generating this wiki page:
The @cellarnode/auth library implements a structured approach to managing authentication failures, API errors, and UI state transitions. It centralizes error logic within a custom AuthError class and provides various callback hooks in both the core logic and React components to allow consuming applications to respond to authentication events like session expiration, login success, or registration failures.
Sources: src/types.ts, src/auth-client.ts, src/react/login-form.tsx
Core Error Architecture
The system uses a custom exception class to wrap API errors and HTTP failures. This ensures that metadata such as error codes and remaining OTP attempts are preserved through the call stack.
The AuthError Class
The AuthError class extends the standard Error and includes specific fields for programmatic handling:
status: The HTTP status code returned by the server.code: A machine-readable string (e.g.,OTP_INVALID,USER_NOT_FOUND).remainingAttempts: An optional number indicating how many more attempts the user has (specifically for OTP verification).
Sources: src/types.ts:38-48
API Error Parsing
The AuthClient includes a private parseErrorResponse function that attempts to extract structured error information from the JSON response body. If the body is not valid JSON or lacks the expected fields, it defaults to an UNKNOWN code with the HTTP status.
Sources: src/auth-client.ts:7-25
The diagram shows the logic flow within the AuthClient fetch wrapper, highlighting the special handling for 401 Unauthorized status codes and structured error throwing. Sources: src/auth-client.ts:27-75
Authentication Callbacks
Callbacks are used to decouple the authentication logic from application-specific side effects like routing or notifications.
Global Callbacks
When creating an AuthClient, developers can provide an onAuthFailure callback. This is triggered when a 401 response occurs and a subsequent token refresh attempt fails.
Sources: src/auth-client.ts:5-6, src/auth-client.ts:68
| Callback | Context | Purpose |
|---|---|---|
onAuthFailure | AuthClientConfig | Triggered when a session is unrecoverable; usually used to redirect to login. |
onLoginSuccess | LoginFormProps | Called when a user successfully verifies an OTP and a token is stored. |
onRegistered | RegisterFormProps | Called after a successful registration request is completed. |
onNavigateLogin | RegisterFormProps | Triggered when the user clicks the "Log in" link within the registration flow. |
onError | LoginFormProps | Optional hook for external error handling (e.g., toast notifications). |
Sources: src/types.ts:58-62, src/react/login-form.tsx:32-55, src/react/register-form.tsx:10-15
React Component Error Handling
The React UI components (LoginForm, RegisterForm) translate AuthError instances into user-facing messages and visual states.
Login Form Logic
The LoginForm maintains internal state for errors and uses a handleAuthError helper to map error codes to human-readable strings.
Sources: src/react/login-form.tsx:112-149
| Error Code | UI Behavior | User Message |
|---|---|---|
USER_NOT_FOUND | Sets isNotFound state | "No account found with this email." |
OTP_INVALID | Shakes input; updates remaining attempts | "Invalid code. X attempt(s) remaining." |
OTP_NOT_FOUND | Resets countdowns | "Code expired. Please request a new one." |
OTP_MAX_ATTEMPTS | Forces new OTP request | "Too many failed attempts. Please request a new code." |
USER_TYPE_MISMATCH | Clears token; calls onError | "This portal is for [type] accounts only." |
Sources: src/react/login-form.tsx:72-78, src/react/login-form.tsx:114-129, src/react/login-form.tsx:180-188
Registration Form Logic
In RegisterForm, errors are primarily handled during the submission of the registration details. It specifically checks for existing accounts.
Sources: src/react/register-form.tsx:34-52
try {
await authApi.register({ name, email, phone, userType });
setSuccess(true);
onRegistered();
} catch (err) {
if (err instanceof AuthError) {
if (err.code === "USER_ALREADY_EXISTS") {
setError("An account with this email already exists. Please log in instead.");
} else {
setError(err.message);
}
}
}
Example implementation of error catching in registration. Sources: src/react/register-form.tsx:38-48
Token Store Error Handling
The AuthStore manages errors related to background token refreshing.
- Refresh Failures: If a background refresh request (
/auth/refresh) fails, the store clears theaccessTokento prevent further authenticated requests with an expired token. - Deduplication: The store uses a
refreshPromiseto ensure that multiple concurrent calls toensureAccessToken(true)do not trigger multiple network requests.
Sequence of events during a forced token refresh failure. Sources: src/auth-store.ts:21-43
Summary
Error handling in @cellarnode/auth is designed to be resilient and informative. By utilizing the AuthError class, the library ensures that technical details (like HTTP status) and business logic (like remaining OTP attempts) are available to both the core authentication client and the React UI layer. The extensive use of callbacks allows developers to easily integrate the library into existing routing and notification systems.