DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk4 min

How Promise Rejections Propagate Through Nested Chains

A Promise rejection passes through chained links without a rejection handler. See how catch return values, thrown errors, nested Promises, and separate branches affect the outcome.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A rejected Promise stays rejected through each chained .then() that has no rejection handler. A .catch() can recover that chain by returning normally, or keep it rejected by throwing or returning a rejected Promise. Each call creates a new Promise, so the important question is what state each link returns—not whether a catch changes the original Promise.

How rejection moves from one Promise to the next

Every call to .then() returns a new, derived Promise. It does not change the Promise on which .then() was called. When the source Promise is rejected, JavaScript looks for a callable rejection handler at that link:

  • If there is no callable rejection handler, the derived Promise rejects with the same reason.
  • If a rejection handler runs and returns a non-thenable value, the derived Promise fulfills with that value. An implicit return of undefined counts as a normal return.
  • If the handler throws, the derived Promise rejects with the thrown value.
  • If it returns a Promise or another thenable, the derived Promise adopts that thenable’s eventual state and result.

These are the Promise rules described in MDN’s Promise.prototype.then() reference and Promise reference.

Trace a rejection one link at a time

Promise.reject(new Error("original"))
  .then(value => value)                  // no rejection handler: remains rejected
  .then(value => value)                  // still rejected; fulfillment callbacks are skipped
  .catch(error => {
    console.error(error);                // handles this link
    return "fallback";                   // this catch's Promise fulfills
  })
  .then(value => console.log(value));    // receives "fallback"

The first two .then() calls have no rejection handlers, so each returned Promise stays rejected with the original reason. .catch(handler) is equivalent in behavior to .then(undefined, handler); it handles the rejection at its own link. Because the handler returns "fallback", the Promise returned by .catch() fulfills, and the next fulfillment callback receives that value. The original rejected Promise remains rejected. MDN documents catch behavior in its Promise.prototype.catch() reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why code after a catch can run

A catch is not only an error logger: its return value determines the state of the Promise it returns. Returning a fallback value—including implicitly returning undefined—handles the rejection and makes the next link a fulfillment path.

Promise.reject(new Error("failure"))
  .catch(error => {
    console.error(error);
    // implicit return undefined: recovered
  })
  .then(() => console.log("This runs"));

To keep the chain rejected after logging or adding context, throw from the handler or return a rejected Promise. A later catch can then handle that new rejection:

Promise.reject(new Error("failure"))
  .catch(error => {
    console.error(error);
    throw error;
  })
  .catch(error => console.log("Still rejected:", error));

Return nested asynchronous work so its rejection joins the chain

When a handler starts another asynchronous operation, return its Promise if subsequent chain steps depend on its result or failure:

fetchData()
  .then(data => {
    return saveData(data);
  })
  .catch(handleError);

Returning saveData(data) makes the Promise from .then() adopt that operation’s eventual outcome. If saveData rejects, the downstream catch can handle the rejection. By contrast, if the callback calls saveData(data) without returning it, the callback itself completes normally—typically with undefined—and the outer chain does not wait for that inner Promise. Its rejection is not carried by that chain, and later steps may run before the save finishes. MDN’s Using promises guide explains this floating-Promise pitfall.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A catch handles one branch, not every branch

Calling .then() or .catch() more than once on the same Promise creates separate derived Promises. Handling one branch does not recover another:

const source = Promise.reject(new Error("failure"));
const recoveredBranch = source.catch(() => "fallback");
const stillRejectedBranch = source.then(value => value);

recoveredBranch fulfills with "fallback". stillRejectedBranch has no rejection handler at its link, so it remains rejected. A catch attached to recoveredBranch would not handle stillRejectedBranch; attach handling to the branch whose rejection you need to address. An unhandled branch may also be reported by the runtime.

A reliable method for tracing a nested chain

  1. Name each Promise. Call the starting Promise p0, then label each returned Promise p1, p2, and so on.
  2. Check the source state at each link. A fulfillment handler runs for fulfillment; a rejection handler runs for rejection. If the relevant handler is absent or not callable, the derived Promise preserves the source state and value or reason.
  3. Record the handler’s outcome. A normal return of a non-thenable fulfills the derived Promise; a returned Promise or thenable is adopted; a thrown value rejects it.
  4. Follow the returned Promise. A later catch handles a rejection only if it is attached to that Promise’s chain or branch.
  5. Check nested work. If a handler starts asynchronous work, verify that it returns the inner Promise when the outer chain must wait for or handle its result.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Promise semantics versus unhandled-rejection reports

Promise propagation rules determine the state of each derived Promise. Runtime notifications are a separate reporting layer. MDN describes the browser unhandledrejection event for a rejected Promise without a handler available at the relevant check, and rejectionhandled when a handler is attached later. In Node.js, the corresponding process-level event is named unhandledRejection. Event names and runtime behavior differ by environment and version; consult the documentation for the specific browser or Node.js version you target. These notifications do not change how a rejection propagates through a chain. Logging an event is not a substitute for handling the relevant branch in application code.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.