Error Handling #2 — AggregateError, Error-First Callbacks & Promise Errors

AggregateError for Promise.any, error-first callback convention, custom error hierarchies, error recovery in .catch(), Error.cause chaining, and unhandled rejection handling.

9 min read
JavaScript
Error Handling
Patterns
Promises

TABLE OF CONTENTS

JavaScript has a rich error system beyond try/catch. This article focuses on the patterns interviewers ask about: AggregateError, the error-first callback convention, custom error hierarchies, and how errors flow through Promises.

Prerequisite: JS Foundations #6 — Error Handling covers try/catch/finally, custom error classes, and global error listeners.


1. AggregateError — Multiple Errors at Once

AggregateError bundles multiple errors into one. It's used by Promise.any when all promises reject.

Loading editor...

Constructor: new AggregateError(errors, message?, options?)errors is an iterable of Error objects.

Interview use: Implementing Promise.any (#18). When all promises reject, reject with an AggregateError containing all the individual rejection reasons.


2. Error-First Callback Convention

Node.js APIs use the pattern callback(err, result):

  • If the operation succeeds, err is null/undefined and result holds the value.
  • If it fails, err is an Error and result is ignored.

Loading editor...

Interview use: Implementing promisify() (#19) — wrapping a callback-based function so it returns a Promise.


3. Custom Error Hierarchies

Creating a family of related errors lets callers catch by type:

Loading editor...

Interview use: promiseTimeout() (#20) uses TimeoutError so callers can distinguish timeout from other failures.


4. Errors in Promise Chains

.then(onFulfilled, onRejected) — Two Handlers

Loading editor...

.catch(onRejected) — Shorthand for .then(null, onRejected)

Loading editor...

Error Recovery in .catch()

.catch() can recover by returning a value:

Loading editor...

Rethrowing in .catch()

To handle only a specific error and let others propagate:

Loading editor...

Interview use: Error propagation in mapAsyncLimit (#21) — reject the outer promise on first error but allow in-flight operations to complete (or short-circuit).


5. Unhandled Promise Rejections

When a promise rejects and nothing catches it:

Loading editor...


6. Error Cause (ES2022)

The cause option lets you chain errors — useful for wrapping low-level errors with context:

Loading editor...


7. Synchronous Throw in Promise Constructors

Throwing inside the Promise executor is automatically caught and rejects the promise:

Loading editor...

Interview use: promisify() (#19) — if the original callback-based function throws synchronously, the Promise constructor catches it.


Quick Reference

PatternUse
AggregateError(errors, msg)Bundle multiple errors (Promise.any)
Error-first callback (err, result)Node.js async convention
class X extends ErrorCustom error types
.catch(err => ...) in Promise chainsError handling and recovery
throw err inside .catchRethrow after selective handling
new Error(msg, { cause: err })Error chaining with context
unhandledrejection eventGlobal unhandled promise listener

Interview Tips

  • Use AggregateError for Promise.any — it's the only combinator that uses it. Know the constructor: new AggregateError(errorsArray, message).
  • Distinguish error types with instanceof — not err.name or err.message parsing.
  • Catch in Promise chains, not in try/catchtry/catch around an async function without await won't catch Promise rejections.
  • Rethrow to let other handlers work — only catch what you can handle.

Related Articles


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI