Promise.prototype.catch()
catch(onRejected) Returns:
Promise · Added in ves6 · Updated March 15, 2026 · Async APIs promise async es6 javascript
The catch() method attaches a callback function that handles Promise rejection. It is essentially a shorthand for promise.then(null, onRejected) but is more readable and the preferred way to handle errors in Promise chains.
Syntax
promise.catch(onRejected)
promise.catch(reason => {
// handle error
})
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
onRejected | function | undefined | Called if the Promise is rejected. Receives the rejection reason (error) as an argument. |
Return Value
A new Promise that:
- Resolves with the return value of
onRejectedif it does not throw - Resolves with the original fulfillment value if the original Promise resolved
- Rejects with the error thrown by
onRejectedif it throws
Examples
Basic Error Handling
fetch("/api/user")
.then(response => response.json())
.catch(error => {
console.error("Failed to fetch user:", error.message);
});
Chaining After Multiple Operations
fetch("/api/data")
.then(data => validate(data))
.then(processed => save(processed))
.then(result => console.log("Success:", result))
.catch(error => {
console.error("Operation failed:", error.message);
});
Recovering from Errors
fetch("/api/user")
.then(response => response.json())
.catch(error => {
// Return default user on failure
return { name: "Guest", id: 0 };
})
.then(user => {
console.log("User:", user.name); // Works even if fetch failed
});
Catching Specific Errors
async function getData() {
try {
const response = await fetch("/api/data");
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return await response.json();
} catch (error) {
if (error.message === "HTTP 404") {
return { data: [] }; // Handle missing gracefully
}
if (error.message === "HTTP 500") {
throw new Error("Server error - please try again later");
}
throw error;
}
}
Short-circuiting a Chain
Promise.resolve(10)
.then(x => {
if (x > 5) throw new Error("Too big");
return x;
})
.catch(error => {
console.log(error.message); // "Too big"
return 0; // Recover with default
})
.then(x => {
console.log(x); // 0 - chain continues!
});
Using with finally
fetch("/api/resource")
.then(response => response.json())
.catch(error => {
console.error("Error:", error.message);
return null;
})
.finally(() => {
console.log("Request completed"); // Always runs
});
Common Mistakes
Not Returning in catch
// WRONG: Lost error, but also breaks the chain
fetch("/api/data")
.then(data => process(data))
.catch(error => {
console.error(error.message);
})
.then(result => {
console.log(result); // undefined if error occurred!
});
// CORRECT: Return a value or re-throw
fetch("/api/data")
.then(data => process(data))
.catch(error => {
console.error(error.message);
return null; // Recover with null
})
.then(result => {
console.log(result); // null if error occurred, or actual result
});
Swallowing Errors
// BAD: Silently ignoring errors
fetch("/api/data").catch(() => {});
// BETTER: At least log something
fetch("/api/data").catch(err => console.warn("Error:", err));
// BEST: Handle appropriately
fetch("/api/data")
.then(data => render(data))
.catch(error => showErrorToast(error.message));
Placing catch Before other then Handlers
// WRONG: catch might catch errors from later in the chain
fetch("/api/user")
.catch(error => console.error(error))
.then(user => user.name) // This can still throw!
.then(name => console.log(name));
// CORRECT: catch at the end
fetch("/api/user")
.then(user => user.name)
.then(name => console.log(name))
.catch(error => console.error(error));
See Also
- Promise.prototype.then() — The foundation of Promise chaining
- Promise.prototype.finally() — Run code regardless of outcome
- Promise.resolve() — Create resolved Promises
- Promise.reject() — Create rejected Promises