한국어
Youngkwang Yang

A personal tech blog

Contents

Three ways async errors slip past you

Tooling

try/catch feels like a safety net, and most of the time it is. But async code has a few holes where an error falls straight through. Here are the three that have bitten me.

1. Forgetting to await

If you call an async function without await inside a try, the promise rejects after the try block has already exited. The catch never runs.

try {
  doAsyncThing(); // no await — rejection escapes this try
} catch (err) {
  // never reached
}

2. Errors inside a forEach callback

Array.forEach ignores the promise its callback returns. Throw inside it and the loop shrugs.

items.forEach(async (item) => {
  await save(item); // a rejection here goes nowhere
});

3. The unhandled rejection you never see

A rejected promise with no .catch does not crash the program the way a thrown error does. It logs a warning and moves on, so it is easy to miss in development.

None of these are exotic. They are the ordinary result of async looking synchronous while behaving otherwise. When in doubt, follow the promise: if nobody awaits it, nobody catches it.