w3docs logo

JavaScript Error handling, "try..catch"

Even the greatest programmers can have errors in the scripts. Generally, errors can occur as a result of mistakes, unexpected user input, and a thousand other reasons.

But, hopefully, there exists a try..catch syntax construct, allowing to catch errors, so the script can do something more reasonable.

The syntax of try...catch

Two blocks are included in thetry..catch construct: try and catch:

try {
  // code
} catch (err) {
  // error handling

The code works in the following order:

  1. The code is executed in try {...}.
  2. catch(err) is ignored if there are no errors. The execution gets to the end of the try and continues, skipping the catch.
  3. In case there is an error, the execution of try is stopped. The control flows to the start of catch(err). So, the err variable (any name can be given to it) will involve an error object that includes details about what happened.

The process is illustrated in the picture below:

Let’s check out examples. In the first example, there is no error:

w3docs logo Javascript try...catch error handling
try { console.log('Start test runs'); // no errors here console.log('End test runs'); } catch (err) { console.log('Catch ignores because there are no errors'); }

In the second example, error detection is demonstrated like this:

w3docs logo Javascript try...catch error handling
try { console.log('Start test runs'); anyVar; // error, variable isn't defined console.log('End of test (never reached)'); } catch (err) { console.log(`Error has occurred`); }

Note that try..catch works only for runnable codes. That is, it works in the valid JavaScript.

If the code is syntactically wrong. For example:

w3docs logo Javascript try...catch error handling
try { ((((((((( } catch (e) { console.log("The engine does not understand this code, it is invalid"); }

In the example above, you can see unmatched curly braces.

Generally, the engine of JavaScript first reads the code and then runs it. The errors, occurring in the reading phase are known as “parse-time” errors. They are unrecoverable as the engine doesn’t understand the code.

So, try..catch only catches errors happening in a valid code. Errors like this are known as “runtime errors” or “exceptions”.

Error Object

Once an error happens, JavaScript creates an object, involving the details about it. Then, the object is passed as an argument to catch, like this:

try {
} catch (err) { //the "error object", could use another word instead of err

The error object includes two primary properties for all built-in errors: name (the error name) and message (the textual message about the details of the error).

Other non-standard properties are also available in most environments. One of the most commonly used properties is stack: a string, containing information about the sequence of nested that led to an error. As a rule, developers use it for debugging purposes. Here is an example:

w3docs logo Javascript error handling
try { anyVariable; // error, variable isn't defined } catch (err) { console.log(err.name); // ReferenceError console.log(err.message); // anyVariable is not defined console.log(err.stack); // ReferenceError: anyVariable is not defined at (...call stack) // May also show an error in general console.log(err); // ReferenceError: anyVariable is not defined }

The Usage of “try…catch”

You have already learned from previous chapters that JavaScript supports the JSON.parse(str) method for reading JSON-encoded values.

As a rule, it is used for decoding data, received over the network, either from the server or another source.

It is received and called JSON.parse, as follows:

w3docs logo Javascript JSON.parse
let json = '{"name":"John", "age": 25}'; // data from the server let user = JSON.parse(json); // convert text view to js object //now the user is an object with properties from the string console.log(user.name); // John console.log(user.age); // 25

In case json is malformed, JSON.parse creates an error, and the script “dies”. To get out of such a situation, you can use try..catch, like this:

w3docs logo Javascript try...catch error handling
let json = "{ bad json }"; try { let user = JSON.parse(json); // an error occurs.. console.log(user.name); // doesn't work } catch (e) { //the execution jumps here console.log("Our apologize, there are errors in the data, we will try to request them again."); console.log(e.name); console.log(e.message); }

Throwing errors

Let’s check out a case when json is syntactically correct but doesn’t include a required name property:

w3docs logo Javascript throwing errors
let json = '{ "age": 25 }'; // incomplete data try { let user = JSON.parse(json); //no errors console.log(user.name); // no name } catch (e) { console.log("doesn't execute"); }

Although JSON.parse runs normally here, but the absence of the name is considered an error.

For unifying the error handling process, you can use the throw operator.

“Throw” Operator

The throw operator is used for generating an error. The syntax of the throw operator is the following:

throw <error object>

Technically, anything can be used as an error object. It can even be a primitive such as a number or a string. However, it would be best if you used objects, preferably including name and message properties.

Also, JavaScript has multiple built-in constructors for standard errors: SyntaxError, Error, ReferenceError, and so on.

Their syntax looks like this:

let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);

For-built-in errors the name property is the constructor name. The message should be taken from the argument, like this:

w3docs logo Javascript try..catch error handling
let error = new Error("Things happen"); console.log(error.name); // Error console.log(error.message); // Things happen

JSON.parse generates this kind of error:

w3docs logo Javascript try..catch SyntaxError handling
try { JSON.parse("{ bad json }"); } catch (e) { console.log(e.name); // SyntaxError console.log(e.message); // Unexpected token b in JSON at position 2 }

So, it’s a SyntaxError.

Now, let’s see how to throw the error:

w3docs logo Javascript try..catch SyntaxError handling
let json = '{ "age": 25 }'; // incomplete data try { let user = JSON.parse(json); // no errors if (!user.name) { throw new SyntaxError("Incomplete data: no name"); } console.log(user.name); } catch (e) { console.log("JSON Error: " + e.message); // JSON Error: Incomplete data: no name }


Above it was shown how to handle error using try..catch. But, it is possible that another unexpected error occurs inside the try {...} block. let’s check out a case:

let json = '{ "age": 35 }'; // not complete data
try {
  user = JSON.parse(json); // missed the "let" before the user
} catch (err) {
  console.log("JSON Error: " + err); // JSON Error: ReferenceError: no user is defined

So, programmers can make mistakes. Anytime a bug may be found out and lead to hacks.

Luckily, it is possible to find out what error you get, for example from the name, like here:

try {
  user = { /*...*/ };
} catch (e) {
  console.log(e.name); // "ReferenceError" for accessing an undefined variable

The catch is only capable of processing errors that it recognizes and rethrowing others.

See how catch handles only SyntaxError in the example below:

w3docs logo Javascript try..catch SyntaxError handling
let json = '{ "age": 25 }'; // not complete data try { let user = JSON.parse(json); if (!user.name) { throw new SyntaxError("Incomplete data: no name"); } anyFunc(); // unexpected error console.log(user.name); } catch (e) { if (e.name == "SyntaxError") { console.log("JSON Error: " + e.message); } else { throw e; // rethrow } }

The technique of rethrowing can be explained in the following steps:

  1. All the errors are got by the catch.
  2. The error object err is analyzed in the catch(err) {...} block.
  3. In case you don’t know how to handle it, it will be thrown.

In the example below, you can see the process of rethrowing in a way that only SyntaxError is handled by the catch.

w3docs logo Javascript try..catch SyntaxError handling
let json = '{ "age": 25 }'; // incomplete data try { let user = JSON.parse(json); if (!user.name) { throw new SyntaxError("Incomplete data: no name"); } anyFunc(); //error console.log(user.name); } catch (e) { if (e.name == "SyntaxError") { console.log("JSON Error: " + e.message); } else { throw e; // rethrow } }

The catch block is capable of catching only the errors that it knows how to work with. So, it skips all the others.

Let’s see another example where errors like that are taught by another level of stry..catch:

w3docs logo Javascript errors try..catch
function readData() { let json = '{ "age": 25 }'; try { //... anyFunc(); // error } catch (e) { //... if (e.name != 'SyntaxError') { throw e; // rethrow } } } try { readData(); } catch (e) { console.log("External catch got: " + e); }

The readData can handle only SyntaxError, while the outer try..catch is able handle anything.


The construct of try..catch has another code clause, known as finally.

In case finally is detected, it will execute cases like:

  1. If there were no errors, after try.
  2. If there were errors- after the catch.

The extended syntax of finally is the following;

try {
  ...  try to execute the code
catch (e) {
  ...handle errors
finally {
  ...execute always

Running this code will look as follows:

w3docs logo Javascript try..catch..finally property
try { console.log('try'); if (confirm('To make an error?')) BAD_CODE(); } catch (e) { console.log('catch'); } finally { console.log('finally'); }

The finally clause is generally used when one begins to do something and wishes to finalize it regardless of the outcome.

Let’s check out an example of using finally in case of successful execution of fib, and in case of an error:

w3docs logo Javascript try..catch..finally property
let num = +prompt("Enter a positive integer number?", 20); let diff, result; function fib(n) { if (n < 0 || Math.trunc(n) != n) { throw new Error("Must not be negative as well as integer."); } return n <= 1 ? n : fib(n - 1) + fib(n - 2); } let start = Date.now(); try { result = fib(num); } catch (e) { result = 0; } finally { diff = Date.now() - start; } console.log(result || "error occurred"); console.log(`execution took ${diff}ms`);

So, the function can end with return or throw, it doesn’t matter. The finally clause can run in both of the cases.

Also, you should take into account that the variables such as result and diff in the code above should be before try..catch.

In case of putting let in the try block, it will be noticeable only inside of it.

Global Catch

The information in this part is not a part of core JavaScript but it can also be useful for you.

For fatal errors occurring outside try..catch, there is another way to deal with them. In browsers, you can appoint a function to the specific window.onerror property, which will execute in case there is an uncaught error. Its syntax will look like this:

window.onerror = function (message, url, line, column, err) {
  // ...

Here is an example of its usage:

<!DOCTYPE html>
  <title>Title of the document</title>
      window.onerror = function(message, url, line, column, err) {
        alert(`${message}\n At ${line}:${column} of ${url}`);
      function readData() {
        badFn(); // Error, something went wrong!

So, the primary role of the global handler window.onerror is not recovering the execution of the script but sending an error message to the developers.


The construct of try..catch allows handling runtime errors. With it, you can run the code and catch errors that might occur.

Also, the errors can be generated with the throw operator. As a rule, it is an error object that inherits from the built-in Error class.

Another essential pattern of error handling is rethrowing. Usually, the catch block knows how to handle specific error types, rethrowing errors that it doesn’t recognize.

Even in the case of not having try..catch, most of the environments allow setting up a global error handler for catching the errors that fall out. But, in case of inheriting, it is possible to use obj instanceof Error for identifying error objects. Hence, it is always better to inherit from it.

Do you find this helpful?