jsguides

Promise.reject()

The Promise.reject() static method returns a Promise object that is rejected with the given reason. It is one of the two Promise resolution methods in JavaScript, alongside Promise.resolve().

Syntax

Promise.reject(reason)

Parameters

  • reason: The reason for the rejection. This can be any JavaScript value, including errors, strings, objects, or undefined.

Return Value

A Promise that was rejected with the specified reason.

Description

Promise.reject() is a static method on the Promise constructor that creates a new rejected Promise immediately, without requiring an executor function. This method exists primarily for consistency with Promise.resolve(), allowing you to create rejected promises in a fluent, functional style.

The method accepts any value as its reason argument. While it is conventional to pass an Error object (or a subclass like TypeError, RangeError), JavaScript does not enforce this. Passing non-Error values is valid but generally discouraged because it loses stack trace information.

When to use Promise.reject()

This method is useful in several scenarios:

  1. Conditional rejection: When a function needs to return a rejected Promise based on some condition, Promise.reject() provides a clean syntax without requiring an async function or executor.

  2. Testing: Creating intentionally rejected Promises is essential for testing error handling code, particularly with methods like Promise.all(), Promise.race(), or custom promise utilities.

  3. API design: Libraries that return Promises can use Promise.reject() to signal failures without exposing internal executor logic.

Comparison with throw

Unlike throwing an error inside an async function (which causes the returned Promise to reject), Promise.reject() creates the rejected Promise explicitly. This can be clearer in conditional logic where you want the rejection path to be immediately visible:

function getData(id) {
  if (!id) {
    return Promise.reject(new Error("ID is required"));
  }
  return fetch(`/api/data/${id}`);
}

The getData function above demonstrates early rejection with Promise.reject() in a synchronous guard clause---no async keyword needed. This pattern keeps the rejection logic at the top of the function where it is easiest to spot during code review. The examples below walk through the method’s core behaviors, starting with the simplest case of creating a rejected promise and catching it.

Examples

Basic Usage

Creating a simple rejected Promise with an Error:

const rejectedPromise = Promise.reject(new Error("Something went wrong"));

rejectedPromise.catch((error) => {
  console.log(error.message); // "Something went wrong"
  console.log(error instanceof Error); // true
});

Passing an Error object gives you a stack trace that points to the line that created the rejection, which makes debugging much easier when the .catch() handler is far from the rejection site. The next example shows what happens when you pass a plain string instead---you lose that trace, but the rejection still propagates through the promise chain.

Using with non-error values

While not recommended, any value can be used as the rejection reason:

const p = Promise.reject("failure reason");

p.catch((reason) => {
  console.log(reason); // "failure reason"
  console.log(typeof reason); // "string"
});

Rejecting with a string might work for a quick prototype, but production code should always reject with an Error so that .catch() handlers can inspect error.stack and error.message consistently. The conditional pattern below shows Promise.reject() used as an early return in a validation function---a clean alternative to throwing inside an async function when you want the rejection to be visible at the top of the function body.

Conditional promise return

The method shines when you need to conditionally return rejected or resolved Promises:

function validateAndFetch(user) {
  if (!user || !user.id) {
    return Promise.reject(new TypeError("Invalid user object"));
  }
  return fetch(`/users/${user.id}`);
}

validateAndFetch({ id: 42 })
  .then((response) => console.log("Success:", response))
  .catch((err) => console.error("Error:", err.message));

The validateAndFetch function shows Promise.reject() in its classic role: bailing out early when preconditions are not met, without needing async/await or a thrown exception. That same idea scales to collections---the next example mixes Promise.reject() with Promise.allSettled() so you can gather both successful values and failure reasons from a batch of promises.

In Promise.all() for error collection

When you need to handle multiple Promises but want to track both successes and failures, you can use Promise.reject() to convert individual failures into the collection:

const results = [
  Promise.resolve(1),
  Promise.reject(new Error("Second failed")),
  Promise.resolve(3)
];

Promise.allSettled(results).then((outcomes) => {
  outcomes.forEach((outcome, index) => {
    if (outcome.status === "fulfilled") {
      console.log(`Promise ${index}:`, outcome.value);
    } else {
      console.log(`Promise ${index}:`, outcome.reason.message);
    }
  });
});

Promise.allSettled() is the right pairing when you want to inspect every outcome, but sometimes you want a timeout that races against the work itself. The final example shows Promise.reject() as the losing entry in a Promise.race(), where it is the deadline---if the real promise does not settle first, the rejection wins and the caller gets a timeout error.

Chaining with Promise.race()

In race conditions where you want a timeout-style rejection:

function withTimeout(promise, ms) {
  return Promise.race([
    promise,
    Promise.reject(new Error(`Timed out after ${ms}ms`))
  ]);
}

const slow = new Promise((resolve) => setTimeout(resolve, 2000));
withTimeout(slow, 100).catch((err) => console.log(err.message)); // "Timed out after 100ms"

See Also