Error handling patterns in Node.js
Error Handling in Node.js
Proper error handling is critical in Node.js. Unhandled errors crash your server. Node.js has several patterns for handling errors depending on the code style.
Error Types
| Type | Description |
|---|---|
| Operational errors | Expected: DB connection failed, invalid input, file not found |
| Programmer errors | Bugs: TypeError, ReferenceError, wrong arguments |
Operational errors should be handled gracefully; programmer errors usually require a restart.
1. Callbacks (Node.js error-first convention)
js
fs.readFile('./file.txt', 'utf8', (err, data) => {
if (err) {
console.error('Failed to read:', err.message);
return; // handle and stop
}
console.log(data);
});The first argument is always the error (or null if none).
2. Promises
js
fetchUser(id)
.then(user => process(user))
.catch(err => console.error('Error:', err.message))
.finally(() => cleanup());3. async/await with try/catch
js
async function getUser(id) {
try {
const user = await fetchUser(id);
const posts = await fetchPosts(user.id);
return { user, posts };
} catch (err) {
console.error('Failed:', err.message);
throw err; // re-throw if needed
}
}4. Express Error Handling
js
// Wrap async route handlers
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
app.get('/user/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) throw new Error('User not found');
res.json(user);
}));
// Centralized error handler
app.use((err, req, res, next) => {
const status = err.statusCode || 500;
res.status(status).json({
error: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
});
});5. Custom Error Classes
js
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode;
this.name = 'AppError';
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} not found`, 404);
}
}
// Usage
throw new NotFoundError('User');6. Global Unhandled Errors
js
// Unhandled Promise rejections (Node.js 15+ crashes by default)
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection:', reason);
// Log and gracefully shutdown
process.exit(1);
});
// Uncaught synchronous exceptions
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err);
process.exit(1); // must exit! state is corrupted
});Best Practices
- Always handle errors — never swallow them silently
- Use custom error classes with status codes
- Centralize error handling in Express with an error middleware
- Log errors with context (request ID, user ID, stack trace)
- Never throw in
process.on('uncaughtException')— gracefully shut down - Use
Promise.allSettled()when some failures are acceptable
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.