Skip to content

How to Fix JavaScript Async/Await Error Handling

DodaTech Updated 2026-06-24 3 min read

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 await calls in try/catch blocks.
  • Use .catch() as an alternative when try/catch is not convenient.
  • Prefer Promise.allSettled over Promise.all for fault-tolerant operations.
  • Register global unhandled rejection handlers in Node.js and browsers.

Common Mistakes with async await

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead 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

### Should I use try/catch or .catch() for async functions?

Both work, but try/catch is cleaner for multiple await calls in sequence. Use try/catch when you want to handle errors at a specific scope level. Use .catch() when you want to attach error handling at the call site without wrapping in a block.

Why does my async function throw but the catch block does not run?

Make sure you are awaiting the async function. Calling myFunc() without await returns a promise, and errors thrown inside the function become promise rejections rather than synchronous exceptions. Either await the call or use .catch() on the returned promise.

How do I handle errors in concurrent async operations?

For multiple independent async operations, use Promise.allSettled() to get results from all promises regardless of rejection. For sequential operations where each depends on the previous, use try/catch around the sequence. Use Promise.any() for race conditions where you need the first successful result.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro