Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to handle errors in async code

Short answer

With await, errors are caught by an ordinary try...catch:

const loadUser = async () => {
  throw new Error('User not found');
};
 
try {
  await loadUser();
} catch (error) {
  console.log('Error:', error.message);
}

Output:

Error: User not found

The catch method

Without await, attach .catch() to the promise:

const loadUser = async () => {
  throw new Error('User not found');
};
 
await loadUser()
  .then((user) => console.log(user))
  .catch((error) => console.log('Error:', error.message));

Output:

Error: User not found

A default value

.catch() can return a replacement value, and the code goes on:

const loadSettings = async () => {
  throw new Error('offline');
};
 
const settings = await loadSettings().catch(() => ({ theme: 'light' }));
 
console.log(settings.theme);

Output:

light

finally

finally runs in any case: convenient for hiding a loading indicator:

let loading = true;
 
try {
  await Promise.reject(new Error('failed'));
} catch (error) {
  console.log(error.message);
} finally {
  loading = false;
}
 
console.log('loading:', loading);

Output:

failed
loading: false

Common mistake

try...catch around a promise without await does not catch anything: the error happens later, when the block has already ended:

const fail = async () => {
  throw new Error('late error');
};
 
try {
  fail().catch((error) => console.log('caught only by .catch():', error.message));
} catch {
  console.log('never runs');
}

Output:

caught only by .catch(): late error

Functions used in this recipe

  • try...catch — Catches errors so the program does not stop.
  • Promise.allSettled — Waits for every promise to settle and reports each result — success or failure.
  • async function — A function that always returns a promise and lets you use await inside.

Thanks for reading!

Donate to the site — we work hard for you.