All topics
Asyncintermediate

Error Handling in Async Code

Strategies for catching and handling errors across callbacks, promise chains, and async/await, including unhandled rejections.

Asynchronous error handling has evolved through three styles — error-first callbacks, .catch() on promise chains, and try/catch around await — each with different failure modes if done wrong.

Handling async errors is a relay of responsibility: error-first callbacks are runners who must check for a dropped baton themselves; a promise chain's .catch is a catcher at the end of the race; try/catch pauses the race the instant a runner trips.

Key Concepts

1
In callback style, the convention is error-first: the callback's first argument is either an error or null, and every implementation must explicitly check it. In promise chains, a rejection skips forward to the nearest .catch(), so one .catch() at the end can handle errors from any step, as long as every step propagates its promise.
2
With async/await, a rejected awaited promise throws like a synchronous exception, so ordinary try/catch works naturally. If unhandled, the async function's own returned promise rejects instead, so the caller must still handle it.
3
A rejected promise with no handler anywhere triggers unhandledrejection or crashes the Node process by default — a real production concern.