How do you handle errors with async/await, and why can try/catch miss some of them?
Wrap await calls in try/catch. The catch only sees rejections that are awaited inside the try. A promise you forget to await, or return without awaiting, escapes the block.
Explain it simply
An await turns a rejected promise back into a thrown error at that exact line. That is why a normal try/catch works around it, and why finally is a good place for cleanup like hiding a loading spinner.
The trap: try/catch only watches the current function's call stack. If you start a promise without await, its failure happens later, outside the try block, and becomes an unhandled rejection.
Same with return promise inside a try: the function returns before the promise settles, so the catch never runs. Write return await promise if you need the catch to apply.
Example
const failing = () => Promise.reject(new Error("network down"));
async function load() {
try {
await failing();
console.log("not reached");
} catch (e) {
console.log("caught: " + e.message); // -> caught: network down
} finally {
console.log("cleanup"); // -> cleanup
}
}
load();
async function leaky() {
try {
failing(); // no await: this rejection is NOT caught here
} catch (e) {
console.log("never printed");
}
}What to say in the interview
"await converts a rejection into a throw, so try/catch/finally works for awaited calls. I make sure every promise is awaited or returned with await inside the try, otherwise the error is unhandled. For many calls I combine with Promise.all or allSettled."
Common mistakes
- Writing try { return fetchData(); } and expecting catch to run on failure.
- Catching an error and silently ignoring it.