Tutorials Logic, IN info@tutorialslogic.com

Unhandled Promise Rejection Fix: Tutorial, Examples, FAQs & Interview Tips

What is Unhandled Promise Rejection?

Unhandled Promise Rejection occurs when a Promise is rejected but there's no .catch() handler or try-catch block to handle the error. This can lead to silent failures and hard-to-debug issues in your application.

Common Causes

  • Missing .catch() handler on promises
  • No try-catch block in async/await functions
  • API request fails without error handling
  • Throwing errors inside promises without catching
  • Chaining promises without final .catch()

Quick Fix (TL;DR)

Quick Solution

Quick Solution
// ❌ Problem - No error handling
fetch('/api/users')
    .then(res => res.json())
    .then(data => console.log(data));

// ✅ Solution 1: Add .catch()
fetch('/api/users')
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));

// ✅ Solution 2: Use async/await with try-catch
async function getUsers() {
    try {
        const res = await fetch('/api/users');
        const data = await res.json();
        console.log(data);
    } catch (error) {
        console.error('Error:', error);
    }
}

Common Scenarios & Solutions

The most common case - making API calls without handling potential errors.

Using async/await without try-catch blocks leads to unhandled rejections.

Long promise chains need a final .catch() to handle any errors in the chain.

When using Promise.all(), if any promise rejects, the entire operation fails.

Problem

Problem
// No error handling - will cause unhandled rejection if API fails
fetch('https://api.example.com/users')
    .then(response => response.json())
    .then(users => {
        console.log(users);
        displayUsers(users);
    });
// If network fails or API returns error, promise is rejected but not caught

Solution

Solution
// Solution 1: Add .catch() at the end
fetch('https://api.example.com/users')
    .then(response => response.json())
    .then(users => {
        console.log(users);
        displayUsers(users);
    })
    .catch(error => {
        console.error('Failed to fetch users:', error);
        showErrorMessage('Unable to load users');
    });

// Solution 2: Handle HTTP errors properly
fetch('https://api.example.com/users')
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.json();
    })
    .then(users => {
        console.log(users);
        displayUsers(users);
    })
    .catch(error => {
        console.error('Error:', error);
        showErrorMessage(error.message);
    });

Problem

Problem
async function loadUserData() {
    const response = await fetch('/api/user');
    const user = await response.json();
    console.log(user);
}

loadUserData(); // If fetch fails, unhandled rejection!

Solution

Solution
// Solution 1: Add try-catch inside function
async function loadUserData() {
    try {
        const response = await fetch('/api/user');
        const user = await response.json();
        console.log(user);
    } catch (error) {
        console.error('Failed to load user:', error);
    }
}

loadUserData();

// Solution 2: Catch when calling the function
async function loadUserData() {
    const response = await fetch('/api/user');
    const user = await response.json();
    return user;
}

loadUserData()
    .then(user => console.log(user))
    .catch(error => console.error('Error:', error));

// Solution 3: Use .catch() on the promise
loadUserData().catch(error => {
    console.error('Error:', error);
});

Problem

Problem
fetch('/api/user')
    .then(res => res.json())
    .then(user => fetch(`/api/posts/${user.id}`))
    .then(res => res.json())
    .then(posts => {
        console.log(posts);
        displayPosts(posts);
    });
// Any error in this chain is unhandled

Solution

Solution
// Add .catch() at the end of the chain
fetch('/api/user')
    .then(res => res.json())
    .then(user => fetch(`/api/posts/${user.id}`))
    .then(res => res.json())
    .then(posts => {
        console.log(posts);
        displayPosts(posts);
    })
    .catch(error => {
        console.error('Error in promise chain:', error);
        showErrorMessage('Failed to load data');
    });

// Or use async/await for cleaner code
async function loadUserPosts() {
    try {
        const userRes = await fetch('/api/user');
        const user = await userRes.json();
        
        const postsRes = await fetch(`/api/posts/${user.id}`);
        const posts = await postsRes.json();
        
        displayPosts(posts);
    } catch (error) {
        console.error('Error:', error);
        showErrorMessage('Failed to load data');
    }
}

loadUserPosts();

Problem

Problem
Promise.all([
    fetch('/api/users'),
    fetch('/api/posts'),
    fetch('/api/comments')
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([users, posts, comments]) => {
    console.log(users, posts, comments);
});
// If any fetch fails, unhandled rejection

Solution

Solution
// Solution 1: Add .catch() to Promise.all()
Promise.all([
    fetch('/api/users'),
    fetch('/api/posts'),
    fetch('/api/comments')
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([users, posts, comments]) => {
    console.log(users, posts, comments);
})
.catch(error => {
    console.error('Failed to load data:', error);
});

// Solution 2: Use Promise.allSettled() (doesn't reject)
Promise.allSettled([
    fetch('/api/users'),
    fetch('/api/posts'),
    fetch('/api/comments')
])
.then(results => {
    results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
            console.log(`Request ${index} succeeded:`, result.value);
        } else {
            console.error(`Request ${index} failed:`, result.reason);
        }
    });
});

// Solution 3: Catch individual promises
Promise.all([
    fetch('/api/users').catch(err => ({ error: err })),
    fetch('/api/posts').catch(err => ({ error: err })),
    fetch('/api/comments').catch(err => ({ error: err }))
])
.then(results => {
    // Handle results, some may have errors
    console.log(results);
});

Global Error Handlers

Global Handler

Global Handler
// Catch all unhandled promise rejections
window.addEventListener('unhandledrejection', event => {
    console.error('Unhandled promise rejection:', event.reason);
    // Log to error tracking service
    // Show user-friendly error message
    event.preventDefault(); // Prevent default browser behavior
});

Node.js Handler

Node.js Handler
process.on('unhandledRejection', (reason, promise) => {
    console.error('Unhandled Rejection at:', promise, 'reason:', reason);
    // Log to error tracking service
    // Optionally exit process
    // process.exit(1);
});

Best Practices

  • Always add .catch() - Every promise chain should end with .catch()
  • Use try-catch with async/await - Wrap await calls in try-catch blocks
  • Handle errors at appropriate level - Catch errors where you can handle them meaningfully
  • Use Promise.allSettled() - When you want all promises to complete regardless of failures
  • Add global handlers - Catch any unhandled rejections as a safety net
  • Log errors properly - Use error tracking services like Sentry
  • Show user-friendly messages - Don't expose technical errors to users

Related Errors

Frequently Asked Questions

Unhandled promise rejection occurs when a Promise is rejected but there's no .catch() handler or try-catch block to handle the error. This can cause silent failures and make debugging difficult.

Add .catch() handler to promise chains or use try-catch blocks with async/await. Every promise should have error handling either inline or at the end of the chain.

In browsers, it logs a warning to console. In Node.js, it logs a warning and may crash the process in future versions. Always handle rejections to prevent unexpected behavior.

.catch() is used with promise chains (.then()), while try-catch is used with async/await. Both serve the same purpose of handling errors, but try-catch provides cleaner syntax with async/await.

Use Promise.all() when you need all promises to succeed. Use Promise.allSettled() when you want to wait for all promises to complete regardless of success or failure.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.