Unhandled Promise Rejection - Complete Fix Guide (2026)
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.
Error Message:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
Common Causes
Quick Fix (TL;DR)
// ❌ 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
Scenario 1: Missing .catch() on Fetch
The most common case - making API calls without handling potential errors.
// 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 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);
});
Scenario 2: Async/Await Without Try-Catch
Using async/await without try-catch blocks leads to unhandled rejections.
async function loadUserData() {
const response = await fetch('/api/user');
const user = await response.json();
console.log(user);
}
loadUserData(); // If fetch fails, unhandled rejection!
// 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);
});
Scenario 3: Promise Chain Without Final .catch()
Long promise chains need a final .catch() to handle any errors in 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);
});
// Any error in this chain is unhandled
// 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();
Scenario 4: Promise.all() Without Error Handling
When using Promise.all(), if any promise rejects, the entire operation fails.
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 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
Browser (Window)
// 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
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
Related Errors
Key Takeaways
- Unhandled promise rejection occurs when promises reject without .catch() handlers
- Always add .catch() at the end of promise chains
- Use try-catch blocks with async/await functions
- Promise.all() rejects if any promise fails - use Promise.allSettled() for partial failures
- Add global unhandledrejection event listener as safety net
- Handle errors at the appropriate level where you can respond meaningfully
Frequently Asked Questions
Level Up Your Javascript Skills
Master Javascript with these hand-picked resources
10,000+ learners
Free forever
Updated 2026
Related JavaScript Topics