Skip to Content
Course content

237: AggregateError for Multiple Errors

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a project recently where we had to fetch a configuration file from three different backup servers. The goal was simple: as long as one of them responded, we were good to go. If all three failed, we needed to log exactly why every single one failed so the DevOps team could figure out if it was a network partition or a credential issue.

The "First Failure" Trap

My first instinct was to use Promise.all(), but as you probably remember, that's a "fail-fast" mechanism. The second one of those servers blinked, the whole thing crashed, and I lost the context of the other requests. That's not what I wanted. I wanted to wait until I knew for sure that none of them worked.

So, I switched to Promise.any(). This is the perfect tool for this because it only rejects if every single promise in the array rejects. I set up a quick test script to simulate three different types of failures:

const fetchFromMirror = (name, shouldFail, errorMsg) => {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error(`${name}: ${errorMsg}`)), 100);
  });
};

async function loadConfig() {
  try {
    await Promise.any([
      fetchFromMirror('Mirror-A', true, 'Connection Timeout'),
      fetchFromMirror('Mirror-B', true, '404 Not Found'),
      fetchFromMirror('Mirror-C', true, 'Invalid SSL Certificate'),
    ]);
  } catch (err) {
    console.log('Something went wrong:', err);
  }
}

loadConfig();

Wait, where are the other errors?

When I ran this, the output was a bit surprising. I expected a list of errors, but I just got a single object logged to the console. If I look closer at the error object, it's not a standard Error; it's an AggregateError.

At first, it looks like a normal error message, but there's a catch. If I try to access err.message, it just says "All promises were rejected". That's frustrating. I don't just want to know that they all failed; I want the specifics of how they failed. I need those timeout and SSL messages I wrote into the promises.

Unpacking the Aggregate

I did a quick dive into the object and found the secret: the errors property. Unlike a standard error, an AggregateError carries an array of all the individual errors that triggered it. It's essentially a container.

Let's adjust the catch block to actually make use of this. I'll use instanceof to make sure we're actually dealing with an AggregateError before we try to iterate over it, just to keep the code robust.

async function loadConfig() {
  try {
    await Promise.any([
      fetchFromMirror('Mirror-A', true, 'Connection Timeout'),
      fetchFromMirror('Mirror-B', true, '404 Not Found'),
      fetchFromMirror('Mirror-C', true, 'Invalid SSL Certificate'),
    ]);
  } catch (err) {
    if (err instanceof AggregateError) {
      console.log('All mirrors failed. Detailed breakdown:');
      err.errors.forEach((e, index) => {
        console.error(`Error ${index + 1}: ${e.message}`);
      });
    } else {
      console.error('An unexpected error occurred:', err);
    }
  }
}

loadConfig();

Now we're getting somewhere. Instead of a generic failure message, I can see exactly which mirror had the SSL issue and which one timed out. You can actually throw these yourself too, if you're performing a series of validations and want to report every single validation error back to the user at once, rather than making them fix one error, submit, and find the next one.




📋 Practical Task

Build a Batch User-Validation Reporter

You are building a registration form validator. Instead of throwing an error at the first invalid field, you want to collect all validation errors and throw them as a single AggregateError so the user can fix everything in one go.

Create a function validateUser(user) that checks for the following:

  • user.username must be at least 3 characters long.
  • user.email must contain an "@" symbol.
  • user.age must be 18 or older.

If any of these fail, push a new Error object into an array. If the array is not empty at the end, throw a new AggregateError containing that array of errors. Wrap the function call in a try...catch block that detects the AggregateError and logs each individual validation failure to the console.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.