How to Fix JavaScript Async/Await Error Handling
In this tutorial, you'll learn about How to Fix JavaScript Async/Await Error Handling. We cover key concepts, practical examples, and best practices.
The Problem
Async/await error handling fails when promise rejections are not caught with try/catch, causing unhandled promise rejections that crash Node.js processes or silently fail in browsers.
Quick Fix
Step 1: Wrap await in try/catch
An uncaught rejected promise throws an unhandled error:
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
fetchData();
Uncaught (in promise) TypeError: Failed to fetch
Add try/catch:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error.message);
return null;
}
}
fetchData();
Fetch failed: Failed to fetch
Step 2: Catch errors in the caller
Errors in async functions propagate to the caller:
async function getUser(id) {
const user = await db.findUser(id);
return user;
}
async function loadPage() {
const user = getUser(123);
console.log(user.name);
}
loadPage();
TypeError: Cannot read properties of undefined (reading 'name')
Use try/catch in the caller:
async function getUser(id) {
return await db.findUser(id);
}
async function loadPage() {
try {
const user = await getUser(123);
console.log(user.name);
} catch (error) {
console.error('Failed to load page:', error.message);
}
}
loadPage();
Step 3: Handle promise.all rejections
One rejected promise rejects the entire Promise.all:
async function loadAll() {
const [a, b, c] = await Promise.all([
fetch('/api/a'),
fetch('/api/b'),
fetch('/api/c')
]);
return { a, b, c };
}
Use Promise.allSettled to handle individual failures:
async function loadAll() {
const results = await Promise.allSettled([
fetch('/api/a'),
fetch('/api/b'),
fetch('/api/c')
]);
return results.map(r => r.status === 'fulfilled' ? r.value : null);
}
Step 4: Add a global rejection handler
In Node.js, listen for unhandled rejections:
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled rejection at:', promise, 'reason:', reason);
});
In browsers:
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault();
});
Prevention
- Always wrap
awaitcalls in try/catch blocks. - Use
.catch()as an alternative when try/catch is not convenient. - Prefer
Promise.allSettledoverPromise.allfor fault-tolerant operations. - Register global unhandled rejection handlers in Node.js and browsers.
Common Mistakes with async await
- Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists
These mistakes appear frequently in real-world JS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro