Next

Error Handling

  • Error handling ensures application stability by managing errors centrally and using custom error classes for consistent API responses.

  • Why Handle Errors?

    Errors can occur due to invalid input, system failures, or programming mistakes. Handling them properly ensures your app doesn't crash unexpectedly.

    Key Points:

    • Prevents applications from crashing

    • Provides meaningful feedback to users

    • Makes debugging easier

    • Maintains production stability

    • Ensures proper resource cleanup

    🔹 Common Error Types in Node.js

    Standard JavaScript Errors

    Example:

Common Error Types in Node.js

Node.js errors include standard JavaScript errors like SyntaxError, TypeError, and ReferenceError, as well as system errors such as ENOENT (file not found) and ECONNREFUSED (connection refused), which occur during file or network operations.

// SyntaxError
JSON.parse('{invalid json}');

// TypeError
null.someProperty;

// ReferenceError
unknownVariable;
  • System Errors

// ENOENT: File not found
const fs = require('fs');
fs.readFile('nonexistent.txt', (err) => {
  console.error(err.code); // 'ENOENT'
});

// ECONNREFUSED: Connection refused
const http = require('http');
const req = http.get('http://nonexistent-site.com', (res) => {});
req.on('error', (err) => {
  console.error(err.code); // 'ECONNREFUSED'
});
  • 🔹 Basic Error Handling

    Error-First Callbacks

    Node.js core modules follow this pattern where the first argument of a callback is an error object.

    Example:

Basic Error Handling in Node.js

Handles file read errors using error-first callbacks, ensuring safe execution without crashing.

const fs = require('fs');

function readConfigFile(filename, callback) {
  fs.readFile(filename, 'utf8', (err, data) => {
    if (err) {
      if (err.code === 'ENOENT') {
        return callback(new Error(`Config file ${filename} not found`));
      }
      return callback(err);
    }
    try {
      const config = JSON.parse(data);
      callback(null, config);
    } catch (parseError) {
      callback(new Error(`Invalid JSON in ${filename}`));
    }
  });
}

readConfigFile('config.json', (err, config) => {
  if (err) return console.error('Failed:', err.message);
  console.log('Config loaded:', config);
});
  • 🔹 Modern Error Handling

    Using try…catch with Async/Await

    Example:

Modern Error Handling with Async/Await

Uses try…catch with async/await to handle file read and JSON errors safely, ensuring proper error messages without crashing the app.

const fs = require('fs').promises;

async function loadUserData(userId) {
  try {
    const data = await fs.readFile(`users/${userId}.json`, 'utf8');
    const user = JSON.parse(data);

    if (!user.email) throw new Error('Missing email');

    return user;
  } catch (error) {
    if (error.code === 'ENOENT') throw new Error(`User ${userId} not found`);
    if (error instanceof SyntaxError) throw new Error('Invalid JSON format');
    throw error;
  } finally {
    console.log(`Finished processing user ${userId}`);
  }
}
(async () => {
  try {
    const user = await loadUserData(123);
    console.log('User loaded:', user);
  } catch (error) {
    console.error('Error:', error.message);
  }
})();
  • 🔹 Global Error Handling

    Example:

Global Error Handling in Node.js

Handles uncaught exceptions and unhandled promise rejections globally to prevent crashes and log errors before safely exiting the process.

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);
});

Promise.reject(new Error('Something went wrong'));
  • 🔹 Error Handling Best Practices

    Do’s

    • Handle errors at appropriate levels

    • Log errors with context

    • Use custom error types

    • Clean resources in finally

    • Validate inputs early

    Don’ts

    • Ignore errors or use empty catch blocks

    • Expose sensitive info to clients

    • Use try/catch for flow control

    • Swallow errors without logging

    🔹 Custom Error Classes

    Example:

Custom Error Classes in Node.js

Defines custom error classes like ValidationError and NotFoundError to standardize error handling with specific messages and status codes.

class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
    this.statusCode = 400;
  }
}

class NotFoundError extends Error {
  constructor(resource) {
    super(`${resource} not found`);
    this.name = 'NotFoundError';
    this.statusCode = 404;
  }
}

// Usage
function getUser(id) {
  if (!id) throw new ValidationError('User ID required', 'id');
}
Next