Error Handling
Learn about the error handling system and how to use it effectively in your application.
Overview
The error handling system provides a standardized way to handle and communicate errors across your application. It includes predefined error types, HTTP status codes, and utilities for both server and client-side error handling.
Error Types
AppError
The base error class that all application errors extend from:
class AppError extends Error {
constructor(
message: string,
code: ErrorCode,
statusCode: HttpStatusCode,
context?: Record<string, any>
);
}
Predefined Errors
Common error scenarios are available through the Errors
object:
// Unauthorized access
throw Errors.Unauthorized('Custom message');
// Resource not found
throw Errors.NotFound('User');
// Validation errors
throw Errors.ValidationError('Invalid email format');
// Rate limiting
throw Errors.RateLimitExceeded();
// Database errors
throw Errors.DatabaseError('Failed to create user');
HTTP Status Codes
The system includes standard HTTP status codes for different scenarios:
Code | Constant | Description |
---|---|---|
200 | OK | Request succeeded |
201 | CREATED | Resource created successfully |
400 | BAD_REQUEST | Invalid request |
401 | UNAUTHORIZED | Authentication required |
403 | FORBIDDEN | Permission denied |
404 | NOT_FOUND | Resource not found |
409 | CONFLICT | Resource conflict |
422 | UNPROCESSABLE_ENTITY | Validation failed |
429 | TOO_MANY_REQUESTS | Rate limit exceeded |
500 | INTERNAL_SERVER_ERROR | Server error |
503 | SERVICE_UNAVAILABLE | Service unavailable |
Error Codes
Internal error codes for better error categorization:
Code | Description |
---|---|
UNAUTHORIZED | Authentication/authorization errors |
INVALID_INPUT | Invalid input data |
NOT_FOUND | Resource not found |
ALREADY_EXISTS | Resource already exists |
FORBIDDEN | Permission denied |
SERVER_ERROR | Internal server errors |
RATE_LIMIT_EXCEEDED | Rate limiting |
VALIDATION_ERROR | Data validation errors |
DATABASE_ERROR | Database operation errors |
NETWORK_ERROR | Network-related errors |
Server-Side Error Handling
In Server Actions
import { Errors, handleServerError } from '@/lib/error-utils';
export async function createUser(data: CreateUserInput) {
try {
// Validate input
if (!isValid(data)) {
throw Errors.ValidationError('Invalid user data');
}
// Check permissions
if (!hasPermission()) {
throw Errors.Unauthorized();
}
// Create user
const user = await db.users.create(data);
return user;
} catch (error) {
return handleServerError(error, { userData: data });
}
}
In API Routes
import { ApiResponse } from '@/lib/api-response';
export async function POST(request: Request) {
try {
const data = await request.json();
const user = await createUser(data);
return ApiResponse.success(user, HttpStatusCode.CREATED);
} catch (error) {
return ApiResponse.error(error);
}
}
Client-Side Error Handling
Handling API Responses
import { handleClientError } from '@/lib/error-utils';
async function submitForm(data: FormData) {
try {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json();
throw new AppError(error.message, error.code, response.status);
}
return await response.json();
} catch (error) {
handleClientError(error);
}
}
Best Practices
- Use Predefined Errors: Whenever possible, use the predefined error types from the
Errors
object.
// Good
throw Errors.NotFound('User');
// Avoid
throw new Error('User not found');
- Include Context: Add relevant context when throwing errors to aid debugging.
throw new AppError(
'Failed to process payment',
ErrorCodes.SERVER_ERROR,
HttpStatusCode.INTERNAL_SERVER_ERROR,
{
orderId: '123',
amount: 99.99,
currency: 'USD',
}
);
- Consistent Error Handling: Use the provided utilities consistently across your application.
// In server actions
try {
// ... code
} catch (error) {
return handleServerError(error, context);
}
// In API routes
try {
// ... code
} catch (error) {
return ApiResponse.error(error);
}
// In client code
try {
// ... code
} catch (error) {
handleClientError(error);
}
- Type Safety: Leverage TypeScript to ensure type safety when working with errors.
import { ErrorCode, HttpStatusCode } from '@/lib/errors';
function handleError(code: ErrorCode, status: HttpStatusCode) {
// TypeScript will ensure valid codes are used
}
Error Response Format
API error responses follow a consistent format:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"context": {
"field": "email",
"value": "invalid-email"
}
}
}
Success responses:
{
"success": true,
"data": {
// Response data
}
}
Remember to always handle errors appropriately in your application. Unhandled errors can lead to poor user experience and difficult-to-debug issues.