When the catch block runs
catch runs only when an exception was raised inside its try block. The error may have been thrown manually with throw, or produced by the engine itself, for example a ReferenceError or a TypeError. If try finished cleanly, the catch block is skipped as if it were not there.
Theory
TL;DR
catchfires under exactly one condition: an exception was thrown inside itstry.- The source of the error does not matter: a manual
throwand an automatic engine error are handled the same way. - The error stops
tryon the spot, so the remaining lines of the block never run. - Inside
catch(error)you get the error object withname,messageandstack. - An error outside the
tryblock is not intercepted. - An async error from a callback or from a promise without
awaitis not intercepted either. - If several errors were possible, the first one is handled: execution never reaches the second.
Quick example
try {
console.log("Start");
throw new Error("Something went wrong!");
console.log("This code never runs");
} catch (error) {
console.log("Caught:", error.message);
}Output:
Start
Caught: Something went wrong!The step by step mechanism
- The code inside
try { ... }starts running line by line. - If no error occurs,
catchis never called. - If an error happens inside
try, thetryblock is interrupted immediately and control moves intocatch. - Inside
catch (error)you have the error object, which you can handle, log, or rethrow.
When catch fires
Example 1. There is no error, so catch does not fire:
try {
console.log("Everything works fine!");
} catch (error) {
console.log("Caught an error:", error.message);
}
console.log("Continuing execution...");Output:
Everything works fine!
Continuing execution...Example 2. An automatic engine error:
try {
console.log(a); // ReferenceError: a is not defined
} catch (error) {
console.log("Caught:", error.name); // ReferenceError
}catch fires because JavaScript threw the exception itself when the undeclared variable was accessed.
Example 3. The error cuts try off halfway:
try {
console.log("1");
JSON.parse("not valid json"); // the error is here
console.log("2"); // never runs
} catch (error) {
console.log("Caught:", error.message);
}
console.log("3");Output:
1
Caught: Unexpected token 'o', "not valid json" is not valid JSON
3Example 4. If several errors are possible, the first one is handled:
try {
throw new Error("Error 1");
throw new Error("Error 2"); // never runs
} catch (err) {
console.log("Caught:", err.message);
}Output:
Caught: Error 1When catch does not fire
An error that happens outside the try block has nothing to do with this catch:
try {
console.log("All good inside try");
} catch (error) {
console.log("Caught an error:", error.message);
}
throw new Error("Error outside try!"); // will not be interceptedThe script crashes with an uncaught error, because it was thrown after the statement had already finished.
Asynchronous code
try...catch does not catch errors inside callbacks and promises unless you use await or .catch().
try {
setTimeout(() => {
throw new Error("Error in the callback"); // will not be caught
}, 1000);
} catch (e) {
console.log("Caught:", e.message);
}The setTimeout call itself returns immediately and without an error, while the callback runs later, when the try block is long closed. To catch errors from promises you need async/await or .catch():
async function run() {
try {
await Promise.reject(new Error("Error in the promise"));
} catch (e) {
console.log("Caught:", e.message);
}
}
run();Summary table
| Situation | Does catch run | Reason |
|---|---|---|
No errors in try | No | The code finished normally |
A throw ran inside try | Yes | The exception was raised inside the block |
JavaScript threw the error itself (ReferenceError and friends) | Yes | An automatic runtime error |
The error happened outside try | No | It is not inside the handled region |
An error in a callback or promise without await | No | The async code runs outside the try block |
Common mistakes
- Thinking
catchfires for "any error in the program". It only sees its owntryblock and the calls made synchronously from it. - Wrapping
setTimeoutoraddEventListenerintryand expecting interception. Handle the error inside the callback itself. - Forgetting
awaitbefore an async call. Without it the function only returns a promise, and the rejection becomes an unhandled rejection that bypassescatch. - Expecting the rest of
tryto run after an error. Execution breaks at the failing line and no later line of the block starts. - A silent
catchwith no logging. The error disappears while the bug stays, and finding it becomes far harder.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.