Programming errors are inevitable. Sooner or later, your application will experience some unexpected behavior. Like any other programming language, JavaScript raises errors when something goes wrong in your code.

Errors disrupt the normal flow of an application. But they also help protect your application from unpredictable behavior. Knowing how to handle errors properly is crucial.

Why Is Error Handling Important?

Error handling contributes to an improved user experience. You can swap out JavaScript’s default and sometimes verbose errors with more human-readable error messages of your own. You can gracefully handle the causes of some errors and keep your program running rather than having it quit.

Error handling is also helpful during development. You can catch a runtime error and do something useful with it, like logging it to the browser console. This is more graceful than the error causing a crash and not knowing where or why the error occurred.

Structure of JavaScript Built-In Errors

JavaScript's errors are objects with three properties:

  • name: This is the name of the error. For example, a missing variable name will throw an error called SyntaxError.
  • message: This is the body of the message and explains the error textually.
  • cause: You can use this property with custom errors to keep track of the call stack.

Common Types of Error in JavaScript

Here are some common errors found in JavaScript.

Syntax Error

Syntax errors can occur when JavaScript tries to interpret your code. It will raise an error if your code does not conform to the correct syntax. Some common errors that can raise syntax errors are:

  • Missing variable names.
  • Missing “}” after a function.
  • Missing “)” after a condition.

ReferenceError

Reference errors occur when a program tries to reference a variable that is unavailable or out of scope.

TypeError

JavaScript can throw a type error when it cannot perform an operation because the type it expects is different from the one it receives.

URIError

This error occurs if you use a global URI handling function—like decodeURIComponent()—incorrectly. As a result, the encoding or decoding fails.

AggregateError

This error is used to represent multiple errors wrapped in one. Use it when you want to throw many errors at once. For example, Promise.any() can throw an AggregateError() when all promises passed to it reject.

InternalError

An InternalError is thrown when an error occurs inside the JavaScript engine.

RangeError

Some functions dictate the range of values you can pass as arguments. This error occurs when you try to pass a value that is not included in that range.

Error Handling With the Try...Catch Block

JavaScript provides built-in exception handling functionality with the try…catch…finally block. It also allows you to raise your own errors using the throw operator.

You can use a try…catch block to handle errors that occur during runtime. You write valid code that you expect to execute correctly in the try block. In the catch block, you can write error-handling code.

        try {
    // Valid Javascript code
} catch (error) {
    // Handle error
} finally {
    // Executed even when an error occurs
}

The catch block is ignored if the code in the try block doesn’t raise any errors. If it raises an error, execution jumps to the catch block. Code in the finally block runs whether an error occurs or not. This block is not mandatory, so omit it if you don’t need it.

The code you include in the try block must be valid. If it isn’t, JavaScript will throw a parsing error.

Let’s look at a practical example:

        try {
    console.log(text)
} catch (error) {
    console.log(error.message)
} finally {
    console.log("Will be executed regardless")
}

This program tries to log the value of the text variable. Since that variable is not defined, the program will throw an error. This error is printed on the console in the catch block. The finally block then runs and prints a message of its own.

        ReferenceError: text is not defined
Will be executed regardless

In situations where you need to raise your own error, use the throw operator.

Consider this example that throws an error if the data is falsy:

        const data = getData()
 
try {
    if (!data) {
        throw "No data"
    }
 
    console.log(data)
    // continue
} catch(error) {
    console.log(error) // "No data"
}

In this example, the program calls the getData() function and assigns its result to the data variable. In the try block, the block throws a custom error if the data is empty. The catch block catches that error and logs it to the console.

Throwing errors is very beneficial during development. You can use the custom error message to understand why your application is not working as expected.

As this example demonstrates, you can use a string for the error object. You can actually throw any JavaScript expression as an error. However, for the sake of consistency with built-in errors, use a JavaScript object containing a name and message.

        throw {
    name: "Error name",
    message: "Error message"
}

You can also use JavaScript’s built-in constructors when throwing errors. These constructors include Error, SyntaxError, and ReferenceError, among others.

To throw an error using the Error constructor, use this code:

        throw new Error("No data")

You can now reference the name and message.

        console.log(error.name) // Error
console.log(error.message) // No data

Extending the JavaScript Error Object

A custom error class comes in handy when handling errors that don’t correspond to the objects already provided by JavaScript. For example, you might want to isolate a data validation error as a specific type called ValidationError.

You can use a JavaScript ES2015 class to create a custom error class.

        class ValidationError extends Error {
    constructor(message) {
        super(message);
        this.name = "ValidationError";
    }
}

Throw an error using the ValidationError class like this:

        throw new ValidationError("Your error message")

The thrown error will be an object with the name and message values.

        {
    name: "ValidationError",
    message: "Your error message"
}

Errors Are There to Help

Error handling is a fundamental part of programming, whichever language you’re using. JavaScript has great support for raising and catching errors in the style of exceptions. It also has several built-in error types that you can handle and use for your own cases.

Some errors like syntax errors can go undetected when you are writing JavaScript in “sloppy mode”. Using strict mode allows JavaScript to catch errors that it would have otherwise ignored.