Skip to main content

The try...catch statement

try...catch is the exception-handling statement: everything that may break goes into the try block, and the reaction to the breakage goes into catch. Instead of stopping the whole script, the engine hands control to catch together with the error object, and the program keeps running.

Theory

TL;DR

  • try holds the code that may fail, catch (error) receives the error object and handles it.
  • If no error occurs, the catch block is skipped entirely.
  • Lines in try after the failure point do not run, while the code after the whole statement continues.
  • The optional finally always runs, both after success and after an error.
  • throw lets you raise an exception manually, and the same catch catches it.
  • Only runtime errors of synchronous code inside the block are caught.

Quick example

javascript
try { // code that may fail JSON.parse("not valid json"); } catch (error) { // runs only if an error was thrown console.log("Caught:", error.message); }

The general syntax:

javascript
try { // code where an error may happen } catch (error) { // code that runs if the error happened }

How it works

  1. The code inside try runs line by line.
  2. If an error is thrown inside try, the try block stops and control passes to catch.
  3. If there is no error, the catch block is skipped.
  4. After try...catch the program continues normally.

Example 1. Without try...catch the script crashes:

javascript
console.log("Start"); JSON.parse("not valid json"); // SyntaxError console.log("End"); // never runs

Output:

text
Uncaught SyntaxError: Unexpected token 'o', "not valid json" is not valid JSON

Example 2. With try...catch the script keeps working:

javascript
console.log("Start"); try { JSON.parse("not valid json"); } catch (err) { console.log("Error caught:", err.message); } console.log("End");

Output:

text
Start Error caught: Unexpected token 'o', "not valid json" is not valid JSON End

The error was handled and the script did not crash.

The finally block

A third block, finally, can be added. It always runs, no matter whether an error happened or not.

javascript
try { console.log("Running try"); throw new Error("Failure!"); } catch (err) { console.log("Caught:", err.message); } finally { console.log("This code runs in any case"); }

Output:

text
Running try Caught: Failure! This code runs in any case

finally is most often used to clean resources up: close a connection, stop a timer, delete temporary files, clear a loading state in the UI.

If you do not need the error variable, since ES2019 you may omit it completely:

javascript
try { JSON.parse(raw); } catch { // the fact of the failure matters more than its text return null; }

Raising an exception with throw

try...catch is often combined with the throw operator to raise an exception by hand:

javascript
function divide(a, b) { if (b === 0) throw new Error("Division by zero!"); return a / b; } try { console.log(divide(10, 0)); } catch (e) { console.log("Error:", e.message); }

You may throw any value, but in practice you throw an Error object or a subclass of it: then you get name, message and stack, and instanceof lets you tell error types apart inside catch.

Behaviour details and nested blocks

BehaviourDescription
catch only catches runtime errorsSyntax errors of the script itself (SyntaxError at parse time) are not intercepted
An error inside catch is not caught by the same tryIt has to be wrapped in a second try...catch
try...catch can be nestedDifferent error types are handled at different levels

Example 3. Nested try...catch:

javascript
try { try { throw new TypeError("Wrong type"); } catch (e) { console.log("Inner catch:", e.message); throw new Error("New error"); } } catch (e) { console.log("Outer catch:", e.message); }

Output:

text
Inner catch: Wrong type Outer catch: New error

Summary table

ElementPurpose
tryCode where an error is possible
catchHandles the error if one was thrown
errorThe variable holding the error object
finallyAlways runs, after try and catch
throwRaises an exception that catch catches

Common mistakes

  • Expecting try...catch to catch an error from an async callback. An exception inside setTimeout or an event handler is thrown in a later event loop tick, long after the try block finished. Handle it inside the callback itself.
  • Forgetting await. try { doAsync(); } catch {} catches nothing, because the function only returns a promise. You need try { await doAsync(); } catch {} or a .catch() in the promise chain.
  • An empty catch. Silently swallowing an error hides the bug: at the very least log error or rethrow it.
  • Wrapping half the file in try. The bigger the block, the harder it is to tell what actually broke, and the easier it is to swallow an unrelated failure.
  • return inside finally. It overrides the value returned from try or catch and even suppresses a thrown error, so avoid it.
  • Counting on try...catch against syntax errors. A script with broken syntax never starts, so there is nothing to catch.

Short Answer

Interview ready
Premium

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