๐Ÿš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
๐ŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
JS MASTER CLASS /// MASTER THE ENGINE /// BUILD LOGIC /// ASYNC PATTERNS /// JS MASTER CLASS /// MASTER THE ENGINE ///

Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide

Master Promise-specific error handling: how errors propagate through .then() chains, catching errors in async/await with try/catch, error handling in Promise.all/allSettled, and avoiding swallowed errors.

โšก Total XP: 0|๐Ÿ’ป javascript XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

If you `throw` an error inside a .then() callback, does it crash the program immediately?


๐Ÿš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
๐ŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Error handling in Promise-based and async/await code has its own set of rules and gotchas that differ meaningfully from synchronous try/catch โ€” an error thrown inside a .then() callback, for instance, doesn't behave the way many developers initially expect.

1Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide Part 1

Throwing an error inside a .then() callback doesn't crash your program โ€” it's automatically converted into a rejected Promise, which the next .catch() in the chain receives.

โœ•
โ€”
+
fetchUser()
  .then((user) => {
    if (!user.verified) throw new Error('User not verified');
    return user;
  })
  .catch((err) => console.error(err.message)); // catches the thrown error too
localhost:3000
๐Ÿงต

Throws Become Rejections

2Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide Part 2

A single .catch() at the end of a chain handles a rejection from ANY earlier .then() in that chain โ€” you rarely need a .catch() after every single step.

โœ•
โ€”
+
step1()
  .then(step2)
  .then(step3)
  .catch((err) => {
    // catches a failure from step1, step2, OR step3
  });
localhost:3000

One catch() for the Whole Chain

3Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide Part 3

With async/await, a rejected awaited promise throws an actual exception at that line, so ordinary try/catch works exactly as it does for synchronous code.

โœ•
โ€”
+
async function loadUser() {
  try {
    const user = await fetchUser();
    return user;
  } catch (err) {
    console.error('Failed to load user:', err.message);
  }
}
localhost:3000

try/catch with async/await

4Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide Part 4

A common bug: forgetting to await a promise-returning function call inside a try block means its rejection happens outside the try/catch's ability to intercept it.

โœ•
โ€”
+
async function broken() {
  try {
    fetchUser(); // missing await!
  } catch (err) {
    // never runs โ€” the rejection happens after this function has already returned
  }
}
localhost:3000

The Missing await Bug

5Promise Error Handling Patterns | JavaScript Tutorial - In-Depth Guide Part 5

When handling multiple promises together, choose Promise.all() (fail-fast) versus Promise.allSettled() (every outcome) deliberately based on whether partial failure is acceptable โ€” this decision directly shapes your error-handling code.

โœ•
โ€”
+
// All-or-nothing error handling:
try {
  const [a, b] = await Promise.all([taskA(), taskB()]);
} catch (err) {
  // one failure loses both results
}

// Per-item error handling:
const results = await Promise.allSettled([taskA(), taskB()]);
results.forEach((r) => r.status === 'rejected' && logFailure(r.reason));
localhost:3000

Choosing the Right Combinator

6Step-by-Step Breakdown

Throwing an error inside a .then() callback doesn't crash your program โ€” it's automatically converted into a rejected Promise, which the next .catch() in the chain receives.

Checkpoint: If you throw an error inside a .then() callback, does it crash the program immediately?

  • โ†’Yes, thrown errors inside .then() always crash the script
  • โ†’No, it's converted into a rejected Promise caught by the next .catch()

A single .catch() at the end of a chain handles a rejection from ANY earlier .then() in that chain โ€” you rarely need a .catch() after every single step.

With async/await, a rejected awaited promise throws an actual exception at that line, so ordinary try/catch works exactly as it does for synchronous code.

A common bug: forgetting to await a promise-returning function call inside a try block means its rejection happens outside the try/catch's ability to intercept it.

Checkpoint: If you forget to await a promise-returning call inside a try block, will its eventual rejection be caught by that try/catch?

  • โ†’Yes, try/catch always catches it regardless of await
  • โ†’No, the rejection happens after the try block has already finished

When handling multiple promises together, choose Promise.all() (fail-fast) versus Promise.allSettled() (every outcome) deliberately based on whether partial failure is acceptable โ€” this decision directly shapes your error-handling code.

Next, we'll explore 'Reading Stack Traces'.

Level Up ๐Ÿš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Ensure Every Step of an Async User Flow Has Reachable Error Feedback

In a multi-step async flow (like checkout), verify each awaited step's catch block actually surfaces an accessible error message tied to the relevant step, rather than a single generic catch-all that leaves users unsure which part of the process failed.

SEO Implications

  • 1

    No Direct SEO Effect

    Promise error handling is an application-correctness concern; SEO relevance is limited to preventing broken async data flows behind rendered content.

Best Practices

Always await Promise-Returning Calls Inside a try Block You Expect to Catch Their Errors

A missing await causes the rejection to escape the try/catch entirely, since the function call returns immediately without the try block ever seeing the eventual failure.

Place a Single catch() (or try/catch) at the Appropriate Granularity for Your Error-Handling Needs

Don't scatter redundant .catch() calls after every single .then() unless each step genuinely needs different recovery logic โ€” one well-placed catch usually suffices for a whole chain.

Frequent Bugs

THE BUG

Calling an async function without awaiting it inside a try block, expecting its later rejection to be caught by that surrounding try/catch, when in reality it becomes an unhandled rejection.

THE FIX

Add the missing `await` before the promise-returning call so its rejection is properly funneled into the try/catch as a real thrown exception at that line.

THE BUG

Attaching a .catch() partway through a .then() chain that swallows an error silently (with no re-throw), causing later .then() steps to run as if nothing failed, using stale/undefined data.

THE FIX

Either handle the error fully and provide valid fallback data for later steps, or re-throw it if the chain should not continue after a failure at that point.

Real-World Examples

Correctly Handling a Multi-Step Async Checkout Flow

A checkout process needed to validate a cart, charge a payment method, and create an order, with each step's specific failure needing a distinct, clear error message.

async function checkout(cart, payment) {
  try {
    await validateCart(cart);
  } catch (err) {
    throw new Error('Cart validation failed: ' + err.message);
  }
  try {
    await chargePayment(payment);
  } catch (err) {
    throw new Error('Payment failed: ' + err.message);
  }
  return createOrder(cart, payment);
}

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Missing await causing a try/catch to miss a rejection

try { await fetchUser(); // correct } catch (err) { handle(err); }

The Solution //

Always await promise-returning calls inside a try block meant to catch their failures.

Lesson Glossary

[01]Promise Rejection

A Promise's failed outcome, whether from an explicit reject() call or a thrown error inside a .then().

Code Preview
Promise.reject(err)

[02].catch()

A method attaching a rejection handler to a Promise chain, receiving a rejection from any earlier step.

Code Preview
.catch(handler)

[03]Missing await Bug

Forgetting to await a promise-returning call inside a try block, causing its rejection to bypass that catch.

Code Preview
fetchUser(); // no await

[04]Error Propagation

How a rejection travels through a .then() chain or async/await sequence until handled.

Code Preview
skips to nearest catch

[05]Fail-Fast vs Per-Item Handling

The choice between Promise.all() (one failure loses everything) and allSettled() (every outcome reported).

Code Preview
all() vs allSettled()

Continue Learning