Files
vip-coordinator/docs/ERROR_HANDLING.md
kyle 440884666d
Some checks failed
CI/CD Pipeline / Backend Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Tests (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
docs: Organize documentation into structured folders
Organized documentation into cleaner structure:

Root directory (user-facing):
- README.md - Main documentation
- CLAUDE.md - AI context (referenced by system)
- QUICKSTART.md - Quick start guide

docs/ (technical documentation):
- CASL_AUTHORIZATION.md - Authorization guide
- ERROR_HANDLING.md - Error handling patterns
- REQUIREMENTS.md - Project requirements

docs/deployment/ (production deployment):
- HTTPS_SETUP.md - SSL/TLS setup
- PRODUCTION_ENVIRONMENT_TEMPLATE.md - Env vars template
- PRODUCTION_VERIFICATION_CHECKLIST.md - Deployment checklist

Removed:
- DOCKER_TROUBLESHOOTING.md - Outdated (referenced Google OAuth, old domain)

Updated references:
- Fixed links to moved files in CASL_AUTHORIZATION.md
- Fixed links to moved files in ERROR_HANDLING.md
- Removed reference to deleted BUILD_STATUS.md in QUICKSTART.md

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 17:13:47 +01:00

338 lines
8.9 KiB
Markdown

# Error Handling Guide
This document describes the error handling patterns implemented in the VIP Coordinator application.
## Backend Error Handling
### Global Exception Filters
The backend uses two global exception filters for consistent error responses:
#### 1. HttpExceptionFilter
Handles all HTTP exceptions (4xx, 5xx errors) and formats them consistently.
**Features:**
- Standardized error response format
- Automatic logging with appropriate levels (error/warn/log)
- Request context logging (params, query, body)
- Sensitive data redaction (passwords, tokens, API keys)
**Error Response Format:**
```json
{
"statusCode": 400,
"timestamp": "2026-01-25T10:30:00.000Z",
"path": "/api/v1/events",
"method": "POST",
"message": "Validation failed",
"error": "Bad Request",
"details": { ... }
}
```
#### 2. AllExceptionsFilter
Catch-all filter for unhandled errors (database errors, runtime exceptions, etc.).
**Features:**
- Catches all non-HTTP exceptions
- Prevents server crashes from unhandled errors
- Logs full stack traces
- Returns 500 Internal Server Error to client
- In development: includes stack trace in response
### Using Exceptions in Controllers/Services
**Example:**
```typescript
import { BadRequestException, NotFoundException } from '@nestjs/common';
// Simple error
throw new NotFoundException('VIP not found');
// Error with details
throw new BadRequestException({
message: 'Driver has conflicting events',
conflicts: [
{ id: '123', title: 'Airport Pickup', startTime: '...' }
]
});
```
### Logging Best Practices
```typescript
import { Logger } from '@nestjs/common';
export class MyService {
private readonly logger = new Logger(MyService.name);
async doSomething() {
this.logger.log('Starting operation...');
this.logger.warn('Conflict detected');
this.logger.error('Operation failed', error.stack);
}
}
```
## Frontend Error Handling
### ErrorHandler Utility
The `ErrorHandler` class provides centralized error handling for the frontend.
**Location:** `frontend/src/lib/errorHandler.ts`
### Quick Usage
```typescript
import { handleError } from '@/lib/errorHandler';
try {
await api.createVIP(data);
toast.success('VIP created successfully');
} catch (error) {
handleError('VIP Creation', error, 'Failed to create VIP');
}
```
### Advanced Usage
#### Extract Error Message Only
```typescript
import { ErrorHandler } from '@/lib/errorHandler';
try {
await api.get('/vips');
} catch (error) {
const message = ErrorHandler.getMessage(error, 'Failed to load VIPs');
setErrorMessage(message);
}
```
#### Show Toast Only
```typescript
ErrorHandler.showError(error, 'Operation failed');
```
#### Log Only (No Toast)
```typescript
ErrorHandler.log('VIP Fetch', error, { vipId: '123' });
```
#### Check Error Type
```typescript
try {
await api.updateVIP(id, data);
} catch (error) {
if (ErrorHandler.isAuthError(error)) {
// Redirect to login
navigate('/login');
} else if (ErrorHandler.isConflict(error)) {
// Show conflict resolution UI
const conflicts = ErrorHandler.getConflicts(error);
setConflicts(conflicts);
} else {
ErrorHandler.showError(error);
}
}
```
### Available Methods
| Method | Description | Example |
|--------|-------------|---------|
| `getMessage(error, fallback?)` | Extract user-friendly message | `const msg = ErrorHandler.getMessage(error)` |
| `showError(error, fallback?)` | Show error toast | `ErrorHandler.showError(error)` |
| `log(context, error, info?)` | Log to console with context | `ErrorHandler.log('API', error, { id })` |
| `handle(context, error, fallback?, info?)` | Log + toast | `ErrorHandler.handle('Save', error)` |
| `isAuthError(error)` | Check if 401/403 | `if (ErrorHandler.isAuthError(error))` |
| `isConflict(error)` | Check if 409 | `if (ErrorHandler.isConflict(error))` |
| `isValidationError(error)` | Check if 400 | `if (ErrorHandler.isValidationError(error))` |
| `getConflicts(error)` | Extract conflicts array | `const conflicts = ErrorHandler.getConflicts(error)` |
### API Client Logging
The axios client automatically logs all requests and responses in development mode.
**Console output format:**
```
[API] → POST /api/v1/vips { data: {...} }
[API] ← 201 POST /api/v1/vips { data: {...} }
[API] ✖ 400 POST /api/v1/events { status: 400, data: {...} }
```
**Error types logged:**
- 401: Authentication required
- 403: Permission denied
- 404: Resource not found
- 409: Conflict (with conflict details)
- 500+: Server error
### Migration Guide
#### Before (Old Pattern)
```typescript
try {
await api.createVIP(data);
toast.success('VIP created');
} catch (error: any) {
console.error('Failed to create VIP:', error);
toast.error(error.response?.data?.message || 'Failed to create VIP');
}
```
#### After (New Pattern)
```typescript
import { handleError } from '@/lib/errorHandler';
try {
await api.createVIP(data);
toast.success('VIP created');
} catch (error) {
handleError('VIP Creation', error, 'Failed to create VIP');
}
```
**Benefits:**
- ✅ Consistent error messages across app
- ✅ Automatic console logging with context
- ✅ Handles all error types (Axios, Error, unknown)
- ✅ Type-safe error checking
- ✅ Less code duplication
## Common Error Scenarios
### 1. Network Error (Backend Down)
**Backend logs:** None (backend not reachable)
**Frontend logs:** `[API] ✖ Network error - no response received`
**User sees:** Toast: "Network error. Please check your connection."
### 2. Authentication Error (401)
**Backend logs:** `[WARN] [GET] /api/v1/vips - 401 - Unauthorized`
**Frontend logs:** `[API] ✖ 401 GET /api/v1/vips` + warning
**User sees:** Toast: "Authentication required. Please log in again."
### 3. Permission Error (403)
**Backend logs:** `[WARN] [POST] /api/v1/users - 403 - Forbidden resource`
**Frontend logs:** `[API] ✖ 403 POST /api/v1/users` + warning
**User sees:** Toast: "You do not have permission to perform this action."
### 4. Validation Error (400)
**Backend logs:** `[WARN] [POST] /api/v1/events - 400 - Validation failed`
**Frontend logs:** `[API] ✖ 400 POST /api/v1/events` + response data
**User sees:** Toast: "Validation failed: email must be a valid email"
### 5. Conflict Error (409)
**Backend logs:** `[WARN] [POST] /api/v1/events - 409 - Driver has conflicting events`
**Frontend logs:** `[API] ✖ 409 POST /api/v1/events` + conflicts array
**User sees:** Toast: "A conflict occurred. Please check for overlapping schedules."
### 6. Server Error (500)
**Backend logs:** `[ERROR] [GET] /api/v1/vips - 500 - Internal server error` + stack trace
**Frontend logs:** `[API] ✖ 500 GET /api/v1/vips` + error message
**User sees:** Toast: "Server error. Please try again later."
## Best Practices
### ✅ DO
```typescript
// Use handleError for simple cases
try {
await api.post('/vips', data);
toast.success('Success');
} catch (error) {
handleError('VIP Creation', error);
}
// Use ErrorHandler methods for complex cases
try {
await api.updateEvent(id, data);
toast.success('Event updated');
} catch (error) {
if (ErrorHandler.isConflict(error)) {
// Show conflict resolution dialog
showConflictDialog(ErrorHandler.getConflicts(error));
} else {
ErrorHandler.showError(error);
}
}
// Log errors with context
ErrorHandler.log('Event Update', error, { eventId: id, changes: data });
// Use structured logging in backend
this.logger.log(`Created VIP: ${vip.name} (ID: ${vip.id})`);
this.logger.error(`Failed to create VIP: ${error.message}`, error.stack);
```
### ❌ DON'T
```typescript
// Don't use generic error messages
catch (error) {
toast.error('An error occurred'); // Too vague!
}
// Don't ignore errors
catch (error) {
console.log(error); // Use console.error and proper context
}
// Don't manually extract error messages
catch (error: any) {
const msg = error.response?.data?.message || 'Failed'; // Use ErrorHandler.getMessage()
toast.error(msg);
}
// Don't log sensitive data
this.logger.log(`User login: ${email} with password ${password}`); // Never log passwords!
```
## Debugging Tips
### Enable Verbose Logging
**Backend:** Set `LOG_LEVEL=debug` in `.env`
**Frontend:** Development mode already has verbose logging enabled
### Check Error Context
**Backend logs include:**
- Timestamp
- HTTP method
- URL path
- Status code
- Request params/query/body
- User email (if authenticated)
**Frontend logs include:**
- Timestamp
- Context (feature area)
- HTTP method
- URL
- Request/response data
- Error type
### Common Issues
**"Network error" but backend is running:**
- Check CORS configuration
- Verify API_URL in `.env`
- Check browser DevTools Network tab
**"Authentication required" after login:**
- Check if token is stored in localStorage
- Verify Auth0 configuration
- Check if user is approved in database
**Validation errors don't show field names:**
- Backend DTO needs proper validation decorators
- Use class-validator's @IsString(), @IsEmail(), etc.
---
**Last Updated:** 2026-01-25
**See also:** [CLAUDE.md](../CLAUDE.md) for general project documentation