Get to know MDN better
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
The try...catch statement is comprised of a try block and either a catch block, a finally block, or both. The code in the try block is executed first, and if it throws an exception, the code in the catch block will be executed. The code in the finally block will always be executed before control flow exits the entire construct.
The statements to be executed.
catchStatementsStatement that is executed if an exception is thrown in the try block.
exceptionVar OptionalAn optional identifier or pattern to hold the caught exception for the associated catch block. If the catch block does not use the exception's value, you can omit the exceptionVar and its surrounding parentheses.
finallyStatementsStatements that are executed before control flow exits the try...catch...finally construct. These statements execute regardless of whether an exception was thrown or caught.
The try statement always starts with a try block. Then, a catch block or a finally block must be present. It's also possible to have both catch and finally blocks. This gives us three forms for the try statement:
Unlike other constructs such as if or for, the try, catch, and finally blocks must be blocks, instead of single statements.
A catch block contains statements that specify what to do if an exception is thrown in the try block. If any statement within the try block (or in a function called from within the try block) throws an exception, control is immediately shifted to the catch block. If no exception is thrown in the try block, the catch block is skipped.
The finally block will always execute before control flow exits the try...catch...finally construct. It always executes, regardless of whether an exception was thrown or caught.
You can nest one or more try statements. If an inner try statement does not have a catch block, the enclosing try statement's catch block is used instead.
You can also use the try statement to handle JavaScript exceptions. See the JavaScript Guide for more information on JavaScript exceptions.
When an exception is thrown in the try block, exceptionVar (i.e., the e in catch (e)) holds the exception value. You can use this binding to get information about the exception that was thrown. This binding is only available in the catch block's scope.
It doesn't need to be a single identifier. You can use a destructuring pattern to assign multiple identifiers at once.
The bindings created by the catch clause live in the same scope as the catch block, so any variables declared in the catch block cannot have the same name as the bindings created by the catch clause. (There's one exception to this rule, but it's a deprecated syntax.)
The exception binding is writable. For example, you may want to normalize the exception value to make sure it's an Error object.
If you don't need the exception value, you can omit it along with the enclosing parentheses.
The finally block contains statements to execute after the try block and catch block(s) execute, but before the statements following the try...catch...finally block. Control flow will always enter the finally block, which can proceed in one of the following ways:
If the finally block is entered after a control flow statement (return, throw, break, continue) in the try or catch block, the effect of this statement is deferred until after the last statement executed in the finally block. For example, if an exception is thrown from the try block, even when there's no catch block to handle the exception, the finally block still executes, and the exception is thrown immediately after the finally block finishes executing.
However, there is one exception to this rule: if the last statement executed in the finally block is itself a control flow statement, that statement will override the effect of the previous one (no deferral); see returning from a finally block for examples. It is generally a bad idea to use control flow statements (return, throw, break, continue) in the finally block because they can override the effect of previously executed control flow statements, which is rarely intended. Most of the time, the finally block should be reserved for cleanup code that does not modify the main logic.
When a catch block is used, the catch block is executed when any exception is thrown from within the try block. For example, when the exception occurs in the following code, control transfers to the catch block.
The catch block specifies an identifier (e in the example above) that holds the value of the exception; this value is only available in the scope of the catch block.
You can create "Conditional catch blocks" by combining try...catch blocks with if...else if...else structures, like this:
A common use case for this is to only catch (and silence) a small subset of expected errors, and then re-throw the error in other cases:
This may mimic the syntax from other languages, like Java:
First, let's see what happens with this:
Now, if we already caught the exception in the inner try block by adding a catch block:
And now, let's rethrow the error.
Any given exception will be caught only once by the nearest enclosing catch block unless it is rethrown. Of course, any new exceptions raised in the "inner" block (because the code in catch block may do something that throws), will be caught by the "outer" block.
The following example shows one use case for the finally block. The code opens a file and then executes statements that use the file; the finally block makes sure the file always closes after it is used even if an exception was thrown.
In the same way, the effect of any return statement in the try block is deferred at the end of the finally block, although the return value expression is evaluated before entering the finally block.
The following example illustrates how control flow statements in the finally block behave. When control flow exits the try block via the first return statement, the return value expression (order.sort()) is evaluated before entering the finally block, and the function is planned to return that value after the finally block finishes executing. However, the return statement in the finally block overrides the effect of the previous return statement, including its return value.
The same logic applies to other control flow statements. Here, the function is first planned to throw the value "catch", but instead returns the value "finally".
Again, control flow statements are discouraged in the finally block because this effect is likely not intended.
| ECMAScript® 2027 Language Specification # sec-try-statement |
Enable JavaScript to view this browser compatibility table.
This page was last modified on Mar 9, 2026 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.