Skip to main content

Error Handling & Debugging

Robust error handling is what separates amateur applications from production-ready systems. In this chapter, you’ll learn how to handle errors gracefully, debug effectively, and implement logging strategies.

Understanding Error Types

Operational vs Programming Errors

Critical Distinction: Operational errors should be handled. Programming errors should crash the app (in production, use a process manager to restart).

The Error Class

Every error in JavaScript inherits from the built-in Error class. When you create an error, Node.js automatically captures a stack trace — a breadcrumb trail showing exactly which functions were called and in what order leading up to the error. This stack trace is your most valuable debugging tool.

Custom Error Classes

Async Error Handling Patterns

Callbacks (Legacy)

Promises

Async/Await

Express Error Handling

Centralized Error Handler

404 Handler

Global Error Handlers

These are your application’s last line of defense — safety nets that catch errors which slipped through every other handler. In a well-designed app, these should rarely fire. If they fire frequently, you have unhandled errors upstream that need fixing. Think of these like the emergency shutoff on a factory machine: you hope they never activate, but when they do, they prevent catastrophic damage.
Production tip: Always run your Node.js process behind a process manager like PM2 or inside a container orchestrator. When process.exit(1) fires, the manager automatically restarts the process, minimizing downtime. Without a process manager, your app just stays dead after a crash.

Debugging Techniques

Console Methods

Node.js Debugger

VS Code Debugging

Logging with Winston

console.log is fine during development, but in production you need structured, level-based logging that can write to files, external services, or monitoring platforms. Winston is the most widely used logging library in the Node.js ecosystem. It separates the concept of what you log (levels and messages) from where it goes (transports like console, files, or cloud services).

HTTP Request Logging with Morgan

Structured Logging

Summary

  • Distinguish between operational and programming errors
  • Create custom error classes for different error types
  • Use async wrappers to catch errors in async routes
  • Implement a centralized error handler in Express
  • Handle uncaught exceptions and unhandled rejections
  • Use Winston for structured, configurable logging
  • Debug with VS Code or Chrome DevTools
  • Log meaningful context with each error