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,
errisnull/undefinedandresultholds the value. - If it fails,
erris an Error andresultis 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
| Pattern | Use |
|---|---|
AggregateError(errors, msg) | Bundle multiple errors (Promise.any) |
Error-first callback (err, result) | Node.js async convention |
class X extends Error | Custom error types |
.catch(err => ...) in Promise chains | Error handling and recovery |
throw err inside .catch | Rethrow after selective handling |
new Error(msg, { cause: err }) | Error chaining with context |
unhandledrejection event | Global unhandled promise listener |
Interview Tips
- Use
AggregateErrorforPromise.any— it's the only combinator that uses it. Know the constructor:new AggregateError(errorsArray, message). - Distinguish error types with
instanceof— noterr.nameorerr.messageparsing. - Catch in Promise chains, not in
try/catch—try/catcharound an async function withoutawaitwon't catch Promise rejections. - Rethrow to let other handlers work — only catch what you can handle.