Course contentsShow
← Node.js
Lesson 195 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Custom Error Normalization

You will wrap diverse error objects into a unified class structure for consistent handling across asynchronous chains.

In this lesson, you will learn how to wrap unpredictable, "messy" errors from various asynchronous sources into a single, reliable structure so your application can handle them consistently.

The Problem: The "Wild West" of Errors

When you chain asynchronous promises, errors can come from anywhere: a database driver might throw a string, an HTTP library might throw a plain object, and your own code might throw a standard Error. If your catch blocks have to check what type of error they received every single time, your code becomes messy and fragile.

Normalizing Errors with a Wrapper

"Custom Error Normalization" means creating a central class that forces every incoming error into a predictable format. By doing this, you ensure that no matter where an error originates, your logic always knows it has access to specific properties like statusCode, message, or timestamp.

Implementing the Normalizer

We can create a base AppError class and a utility function to "normalize" anything we catch.

class AppError extends Error {
  constructor(message, status = 500) {
    super(message);
    this.status = status;
    this.isNormalized = true;
  }
}

function normalizeError(err) {
  if (err instanceof AppError) return err;
  
  // Convert strings, objects, or unknown errors into our standard format
  const message = err?.message || String(err) || 'Unknown error occurred';
  return new AppError(message, 500);
}

Usage in Async Chains

Now, when you process a complex chain of promises, you pass your caught errors through this normalizer before deciding how to log or display them.

async function fetchData() {
  try {
    await someUnpredictableTask();
  } catch (rawError) {
    const error = normalizeError(rawError);
    console.error(`Status ${error.status}: ${error.message}`);
    // Now you can safely handle error.status every time!
  }
}

By forcing every error through this filter, you remove the guesswork from your asynchronous flows. You no longer have to worry about whether error.message exists or if the object is just a string; the normalizer guarantees a consistent interface.

Key Takeaway: Custom error normalization transforms unpredictable, chaotic error objects into a predictable class structure, allowing for cleaner and more robust error handling across your entire asynchronous application.