Error Handling with Async/Await

Med

Error handling with async/await uses standard try/catch blocks, making it more intuitive than Promise chains. Any rejected Promise awaited inside a try block will trigger the catch block. This allows for synchronous-style error handling in asynchronous code. Understanding proper error handling patterns is crucial for robust applications.

Interactive Visualization

Path Taken
Error Path
(not taken)
Success Path
(not taken)
Async Call Chain
fetchUserpending
CodeCalling
1async function fetchUser(id) {
2 try {
3 const response = await fetch(`/api/users/${id}`);
4 const user = await response.json();
5 console.log("User:", user.name);
6 return user;
7 } catch (error) {
8 console.log("Error:", error.message);
9 return null;
10 }
11}
12
13fetchUser(123); // Success case
Output
-
We call fetchUser(123). The async function starts executing.
1 / 5
Key Insight: try/catch with await catches both sync errors AND rejected promises - all in one place!

Key Points

  • Use try/catch for async error handling
  • Rejected Promises become thrown exceptions in await
  • catch block receives the rejection reason
  • Can mix await and .catch() on same Promise
  • Re-throw errors to propagate them
  • finally block works as expected for cleanup

Code Examples

Basic try/catch with Async/Await

async function getUser() {
  try {
    const response = await fetch('/api/user');
    
    if (!response.ok) {
      throw new Error('Failed to fetch user');
    }
    
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error:', error.message);
    // Return default or re-throw
    return null;
  }
}

Use try/catch around awaited operations. Rejected Promises are caught as exceptions.

Catching Specific Errors

async function fetchData() {
  try {
    const data = await fetchUser();
    return data;
  } catch (error) {
    if (error.name === 'NetworkError') {
      console.log('Network issue, retrying...');
      return await fetchData(); // Retry
    }
    if (error.status === 404) {
      console.log('User not found');
      return null;
    }
    throw error; // Re-throw unknown errors
  }
}

Check error properties to handle different error types appropriately.

try/catch vs .catch()

// Both work - choose based on context

// Option 1: try/catch (preferred for multiple awaits)
async function method1() {
  try {
    const user = await fetchUser();
    const posts = await fetchPosts(user.id);
    return posts;
  } catch (error) {
    console.error(error);
  }
}

// Option 2: .catch() on specific Promise
async function method2() {
  const user = await fetchUser().catch(() => null);
  if (!user) return []; // Handle specific failure
  
  const posts = await fetchPosts(user.id);
  return posts;
}

try/catch handles multiple awaits. .catch() on a single Promise handles that specific failure.

Finally for Cleanup

async function withLoading() {
  let loading = true;
  
  try {
    const data = await fetchData();
    return data;
  } catch (error) {
    console.error(error);
    throw error; // Re-throw after logging
  } finally {
    loading = false; // Always runs
    console.log('Loading complete');
  }
}

// finally runs whether try succeeds or catch handles

finally block runs after try completes or catch handles, perfect for cleanup.

Common Mistakes

  • Not wrapping await calls in try/catch
  • Forgetting to re-throw errors after logging
  • Catching all errors without differentiation
  • Not handling errors at appropriate level

Interview Tips

  • Know how to use try/catch with await
  • Know when to use .catch() vs try/catch
  • Understand error propagation in async functions
  • Know how to re-throw errors