JavaScript
Promises
Error Handling
Promise.all
Asynchronous Programming

Can I have multiple .finally as well as multiple .catch in Promise.all?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Yes, you can chain multiple .catch() and multiple .finally() calls after Promise.all(), because each of those methods returns a new promise. The important detail is that they do not all handle the same original rejection independently; each one operates on the promise produced by the previous link in the chain.

Think in Terms of a Promise Chain

Promise.all() returns one promise. After that, every .then(), .catch(), or .finally() creates another promise.

So this:

javascript
1Promise.all([taskA(), taskB()])
2  .catch(handleFirst)
3  .catch(handleSecond)
4  .finally(cleanupOne)
5  .finally(cleanupTwo);

is not "two catches attached to the same promise." It is a chain of promises where each handler receives the result of the previous step.

That means:

  • the first .catch() handles rejection from Promise.all() or earlier links
  • the next .catch() only runs if the previous .catch() throws or returns a rejected promise
  • each .finally() runs when the current promise in the chain settles

Multiple .catch() Calls Do Not All See the Same Error

Here is a runnable example:

javascript
1Promise.all([
2  Promise.resolve("ok"),
3  Promise.reject(new Error("boom")),
4])
5  .catch((err) => {
6    console.log("first catch:", err.message);
7    return "recovered";
8  })
9  .catch((err) => {
10    console.log("second catch:", err.message);
11  })
12  .then((value) => {
13    console.log("then:", value);
14  });

Output:

text
first catch: boom
then: recovered

The second .catch() does not run because the first one handled the error and returned a fulfilled value.

If the first catch rethrows:

javascript
1Promise.all([
2  Promise.reject(new Error("boom")),
3])
4  .catch((err) => {
5    console.log("first catch:", err.message);
6    throw new Error("re-thrown");
7  })
8  .catch((err) => {
9    console.log("second catch:", err.message);
10  });

then the second catch runs because the chain became rejected again.

Multiple .finally() Calls Are Also Fine

.finally() is different from .catch() because it does not receive the fulfillment value or rejection reason. It is mainly for cleanup and side effects that should happen regardless of outcome.

javascript
1Promise.all([
2  Promise.resolve(1),
3  Promise.resolve(2),
4])
5  .finally(() => {
6    console.log("cleanup one");
7  })
8  .finally(() => {
9    console.log("cleanup two");
10  })
11  .then((values) => {
12    console.log(values);
13  });

The two finally handlers run in order as the chain settles. They do not replace the result unless they throw an error or return a rejected promise.

That means cleanup code can be layered, but you should still keep it readable. Multiple finally blocks are legal, not automatically a good design.

Use the Chain Intentionally

A useful rule of thumb is:

  • use .catch() when you want to transform or propagate failure
  • use .finally() when you want cleanup that should happen either way

Because the chain is linear, the placement of each handler matters. A catch placed early can convert the rest of the chain back into the fulfilled path. A finally runs regardless, but if it throws, it changes the downstream state too.

Common Pitfalls

  • Thinking multiple .catch() handlers all observe the original Promise.all() rejection independently.
  • Forgetting that a .catch() that returns a value converts the chain back to fulfilled.
  • Using .finally() as if it received the resolved value or rejection reason.
  • Adding many chained handlers when one clear error path and one clear cleanup path would be easier to read.

Summary

  • You can chain multiple .catch() and .finally() calls after Promise.all().
  • Each handler works on the promise returned by the previous step, not independently on the original promise.
  • A .catch() that handles an error can prevent later catches from running.
  • '.finally() always runs on settlement, but it does not receive the chain's value or error.'
  • The key to understanding the behavior is to think in terms of promise chaining, not parallel handlers.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions