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
tryholds the code that may fail,catch (error)receives the error object and handles it.- If no error occurs, the
catchblock is skipped entirely. - Lines in
tryafter the failure point do not run, while the code after the whole statement continues. - The optional
finallyalways runs, both after success and after an error. throwlets you raise an exception manually, and the samecatchcatches it.- Only runtime errors of synchronous code inside the block are caught.
Quick example
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:
try {
// code where an error may happen
} catch (error) {
// code that runs if the error happened
}How it works
- The code inside
tryruns line by line. - If an error is thrown inside
try, thetryblock stops and control passes tocatch. - If there is no error, the
catchblock is skipped. - After
try...catchthe program continues normally.
Example 1. Without try...catch the script crashes:
console.log("Start");
JSON.parse("not valid json"); // SyntaxError
console.log("End"); // never runsOutput:
Uncaught SyntaxError: Unexpected token 'o', "not valid json" is not valid JSONExample 2. With try...catch the script keeps working:
console.log("Start");
try {
JSON.parse("not valid json");
} catch (err) {
console.log("Error caught:", err.message);
}
console.log("End");Output:
Start
Error caught: Unexpected token 'o', "not valid json" is not valid JSON
EndThe 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.
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:
Running try
Caught: Failure!
This code runs in any case
finallyis 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:
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:
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
| Behaviour | Description |
|---|---|
catch only catches runtime errors | Syntax errors of the script itself (SyntaxError at parse time) are not intercepted |
An error inside catch is not caught by the same try | It has to be wrapped in a second try...catch |
try...catch can be nested | Different error types are handled at different levels |
Example 3. Nested try...catch:
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:
Inner catch: Wrong type
Outer catch: New errorSummary table
| Element | Purpose |
|---|---|
try | Code where an error is possible |
catch | Handles the error if one was thrown |
error | The variable holding the error object |
finally | Always runs, after try and catch |
throw | Raises an exception that catch catches |
Common mistakes
- Expecting
try...catchto catch an error from an async callback. An exception insidesetTimeoutor an event handler is thrown in a later event loop tick, long after thetryblock finished. Handle it inside the callback itself. - Forgetting
await.try { doAsync(); } catch {}catches nothing, because the function only returns a promise. You needtry { await doAsync(); } catch {}or a.catch()in the promise chain. - An empty
catch. Silently swallowing an error hides the bug: at the very least logerroror 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. returninsidefinally. It overrides the value returned fromtryorcatchand even suppresses a thrown error, so avoid it.- Counting on
try...catchagainst syntax errors. A script with broken syntax never starts, so there is nothing to catch.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.