Skip to content
How to Fix 'Unhandled Promise Rejection' in JavaScript

How to Fix 'Unhandled Promise Rejection' in JavaScript

DodaTech Updated Jun 15, 2026 3 min read

The Error

Unhandled Promise Rejection: Error: API request failed
Unhandled Promise Rejection: TypeError: Cannot read properties of undefined
(node:12345) UnhandledPromiseRejectionWarning: Error: ...

This warning (or error in Node.js 15+) means a Promise rejected but no .catch() handler or try/catch block was attached to handle the failure. In browsers, unhandled rejections may crash the page. In Node.js, they crash the process.

What Causes It

1. Missing .catch() on Fetch Call

// ❌ No error handler
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data));
// If fetch fails — unhandled rejection!

2. Async Function Error Not Caught

// ❌ try/catch missing in async function
async function loadData() {
  const response = await fetch('/api/data'); // If this throws...
  return response.json();
}
loadData(); // ... this promise rejects with no handler

3. Promise in a Callback

button.addEventListener('click', () => {
  fetch('/api/delete', { method: 'DELETE' })
    .then(r => r.json());
  // No .catch() — rejection goes unhandled
});

4. Promise.all with No Catch

Promise.all([
  fetch('/api/a'),
  fetch('/api/b') // If this fails...
]).then(([a, b]) => console.log(a, b));
// ... Promise.all rejects, and there's no .catch()

How to Fix It

1. Always Add .catch()

The simplest fix — always end promise chains with .catch():

fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    console.error('Request failed:', error);
    showErrorMessage('Failed to load data');
  });

2. Wrap Async Functions in try/catch

async function loadData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
  } catch (error) {
    console.error('Failed to load:', error);
    return null; // Graceful degradation
  }
}

Anticipating confusion: If you call loadData() and want to handle errors from outside, either return the result and let the caller handle it, or return a fallback value as shown above.

3. Handle Errors in Event Listeners

button.addEventListener('click', async () => {
  try {
    const response = await fetch('/api/delete', { method: 'DELETE' });
    console.log('Deleted:', await response.json());
  } catch (error) {
    console.error('Delete failed:', error);
  }
});

4. Add Catch to Promise.all

Promise.all([
  fetch('/api/a'),
  fetch('/api/b')
])
  .then(([a, b]) => console.log(a, b))
  .catch(error => {
    console.error('One or more requests failed:', error);
  });

// Or use Promise.allSettled to handle each result individually
const results = await Promise.allSettled([
  fetch('/api/a'),
  fetch('/api/b')
]);
results.forEach((r, i) => {
  if (r.status === 'rejected') {
    console.log(`Request ${i} failed:`, r.reason);
  }
});

5. Set Up Global Handlers

As a last resort (for errors you missed), set up global handlers:

Browser:

window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled rejection:', event.reason);
  // Log to your error tracking service
  event.preventDefault(); // Prevent default error in console
});

Node.js:

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // Log and clean up
});

Prevention

  1. Always return promises from functions — so callers can attach .catch().
  2. Add .catch() to every .then() chain — make it a habit.
  3. Use async/await with try/catch — it’s harder to forget than .catch().
  4. Enable ESLint’s no-unhandled-promise-rejection rule — catches these statically.
  5. Use Promise.allSettled() instead of Promise.all() when you need to handle individual failures.

ESLint Configuration

{
  "rules": {
    "no-unhandled-promise-rejection": "error"
  }
}

Summary

ScenarioFix
Promise chainAdd .catch() at the end
Async functionWrap in try/catch
Event callbackUse async + try/catch
Promise.allAdd .catch() or use Promise.allSettled
Global safety netAdd unhandledrejection listener

Golden rule: Every Promise should either have a .catch() or be inside a try/catch. No exceptions.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro