Skip to main content

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

  • catch fires under exactly one condition: an exception was thrown inside its try.
  • The source of the error does not matter: a manual throw and an automatic engine error are handled the same way.
  • The error stops try on the spot, so the remaining lines of the block never run.
  • Inside catch(error) you get the error object with name, message and stack.
  • An error outside the try block is not intercepted.
  • An async error from a callback or from a promise without await is not intercepted either.
  • If several errors were possible, the first one is handled: execution never reaches the second.

Quick example

javascript
try { console.log("Start"); throw new Error("Something went wrong!"); console.log("This code never runs"); } catch (error) { console.log("Caught:", error.message); }

Output:

text
Start Caught: Something went wrong!

The step by step mechanism

  1. The code inside try { ... } starts running line by line.
  2. If no error occurs, catch is never called.
  3. If an error happens inside try, the try block is interrupted immediately and control moves into catch.
  4. 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:

javascript
try { console.log("Everything works fine!"); } catch (error) { console.log("Caught an error:", error.message); } console.log("Continuing execution...");

Output:

text
Everything works fine! Continuing execution...

Example 2. An automatic engine error:

javascript
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:

javascript
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:

text
1 Caught: Unexpected token 'o', "not valid json" is not valid JSON 3

Example 4. If several errors are possible, the first one is handled:

javascript
try { throw new Error("Error 1"); throw new Error("Error 2"); // never runs } catch (err) { console.log("Caught:", err.message); }

Output:

text
Caught: Error 1

When catch does not fire

An error that happens outside the try block has nothing to do with this catch:

javascript
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 intercepted

The 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().

javascript
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():

javascript
async function run() { try { await Promise.reject(new Error("Error in the promise")); } catch (e) { console.log("Caught:", e.message); } } run();

Summary table

SituationDoes catch runReason
No errors in tryNoThe code finished normally
A throw ran inside tryYesThe exception was raised inside the block
JavaScript threw the error itself (ReferenceError and friends)YesAn automatic runtime error
The error happened outside tryNoIt is not inside the handled region
An error in a callback or promise without awaitNoThe async code runs outside the try block

Common mistakes

  • Thinking catch fires for "any error in the program". It only sees its own try block and the calls made synchronously from it.
  • Wrapping setTimeout or addEventListener in try and expecting interception. Handle the error inside the callback itself.
  • Forgetting await before an async call. Without it the function only returns a promise, and the rejection becomes an unhandled rejection that bypasses catch.
  • Expecting the rest of try to run after an error. Execution breaks at the failing line and no later line of the block starts.
  • A silent catch with no logging. The error disappears while the bug stays, and finding it becomes far harder.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.