Skip to main content
Practice Problems

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

TypeDescription
Operational errorsExpected: DB connection failed, invalid input, file not found
Programmer errorsBugs: 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

  1. Always handle errors — never swallow them silently
  2. Use custom error classes with status codes
  3. Centralize error handling in Express with an error middleware
  4. Log errors with context (request ID, user ID, stack trace)
  5. Never throw in process.on('uncaughtException') — gracefully shut down
  6. Use Promise.allSettled() when some failures are acceptable

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems