Chapter 10: Error Handling
Chapter 10 of 15
Chapter 10: Error Handling
10.1 Error Handling Patterns
Proper error handling ensures applications fail gracefully and provide useful feedback. Implement consistent error handling across all layers.
Error Types:
- Client Errors (4xx): Invalid requests, authentication failures
- Server Errors (5xx): Application failures, database errors
- Network Errors: Timeouts, connection failures
- Validation Errors: Invalid input data
Error Handling Strategies:
- Try-Catch Blocks: Handle synchronous errors
- Promise Rejection: Handle asynchronous errors
- Error Middleware: Centralized error handling
- Error Boundaries: React component error handling
// Express error middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: {
message: err.message || 'Internal Server Error',
code: err.code || 'INTERNAL_ERROR',
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
}
});
});
// Usage
app.get('/users/:id', async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
const error = new Error('User not found');
error.status = 404;
throw error;
}
res.json(user);
} catch (err) {
next(err);
}
});
Error Response Format:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "User with ID 123 does not exist",
"details": {
"userId": 123
}
}
}
10.2 Logging and Monitoring
Logging and monitoring help track errors, debug issues, and understand application behavior.
Logging Levels:
- DEBUG: Detailed information for debugging
- INFO: General informational messages
- WARN: Warning messages for potential issues
- ERROR: Error messages for failures
- FATAL: Critical errors that may stop application
// Structured logging
logger.info('User logged in', {
userId: user.id,
email: user.email,
ip: req.ip,
timestamp: new Date()
});
logger.error('Database connection failed', {
error: err.message,
stack: err.stack,
database: 'users_db'
});
Logging Best Practices:
- Use structured logging (JSON format)
- Include context (user ID, request ID, timestamp)
- Don't log sensitive information (passwords, tokens)
- Use appropriate log levels
- Centralize logs for analysis
Monitoring Tools:
- Application Monitoring: New Relic, Datadog, AppDynamics
- Error Tracking: Sentry, Rollbar, Bugsnag
- Log Aggregation: ELK Stack, Splunk, CloudWatch
- Performance Monitoring: APM tools, custom metrics
10.3 Error Recovery
Implement strategies to recover from errors gracefully.
Retry Logic:
- Retry transient failures
- Exponential backoff
- Maximum retry attempts
- Good for network and database errors
async function retryOperation(operation, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (err) {
if (i === maxRetries - 1) throw err;
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
}
}
}
Circuit Breaker Pattern:
- Prevent cascading failures
- Stop calling failing service
- Return cached data or default response
- Automatically retry after timeout
10.4 User-Friendly Error Messages
Present errors to users in a clear, helpful way.
- Don't expose technical details to users
- Provide actionable error messages
- Suggest solutions when possible
- Use appropriate HTTP status codes
- Log detailed errors server-side