Robust Error Handling in Node.js
/ 2 min read
Table of Contents
Handling Errors in Node.js Applications
A well-structured error-handling strategy improves application stability, simplifies debugging, and enhances maintainability.
This guide covers:
- Properly handling synchronous and asynchronous errors
- Using middleware for centralized error handling
- Logging errors for better debugging
- Handling uncaught exceptions and rejections
Handling Synchronous Errors
For synchronous code, use try...catch
to prevent crashes.
function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero"); return a / b;}
try { console.log(divide(10, 0));} catch (error) { console.error("Error:", error.message);}
Handling Asynchronous Errors
Using try...catch
inside async functions
async function fetchData() { try { const response = await fetch("https://api.example.com/data"); const data = await response.json(); return data; } catch (error) { console.error("Failed to fetch data:", error.message); }}
Handling Promises with .catch()
fetch("https://api.example.com/data") .then((response) => response.json()) .then((data) => console.log(data)) .catch((error) => console.error("Error:", error.message));
Centralized Error Handling in Express
Using a middleware function allows centralized error handling.
import express, { Request, Response, NextFunction } from "express";
const app = express();
app.use((req, res, next) => { next(new Error("Something went wrong"));});
app.use((error: Error, req: Request, res: Response, next: NextFunction) => { console.error("Error:", error.message); res.status(500).json({ error: error.message });});
Handling Uncaught Exceptions and Rejections
Uncaught exceptions and unhandled rejections can cause the application to crash. Use global handlers to manage them.
Uncaught Exceptions
process.on("uncaughtException", (error) => { console.error("Uncaught Exception:", error); process.exit(1);});
Unhandled Promise Rejections
process.on("unhandledRejection", (reason, promise) => { console.error("Unhandled Rejection:", reason); process.exit(1);});
Logging Errors for Better Debugging
Using a logging library like Winston improves error tracking.
import winston from "winston";
const logger = winston.createLogger({ level: "error", format: winston.format.json(), transports: [ new winston.transports.File({ filename: "error.log" }), new winston.transports.Console(), ],});
logger.error("Something went wrong");
Conclusion
- Use
try...catch
for synchronous and asynchronous errors. - Implement centralized error handling in Express.
- Handle uncaught exceptions and promise rejections globally.
- Use structured logging for better debugging.
A structured error-handling approach ensures that your application remains stable and debuggable in production.