Skip to content

JavaScript Error Handling Interview Questions (try, catch, finally)

In the Error Handling article, we learned how try, catch and finally work. In interviews, the questions are usually about the order things run in, and the cases where try...catch doesn’t do what you’d expect.

Let’s go through them. For every question, try to work out the answer yourself before reading the explanation.

1. In what order do try, catch and finally run?

Section titled “1. In what order do try, catch and finally run?”
try {
    console.log("A");
    throw new Error("Oops");
    console.log("B");
} catch (err) {
    console.log("C", err.message);
} finally {
    console.log("D");
}

console.log("E");

Answer: A, C Oops, D, E

In the above example, you can see that:

  1. A is printed, then the throw happens.
  2. As soon as an error is thrown, JavaScript skips the rest of the try block. That’s why B never prints.
  3. Control jumps to catch, which prints C with the error message.
  4. finally always runs, so D is printed.
  5. Since the error was handled, the program keeps going and prints E.

2. Does finally run after return in JavaScript?

Section titled “2. Does finally run after return in JavaScript?”
function test() {
    try {
        return "from try";
    } finally {
        console.log("finally runs");
    }
}

console.log(test());

Answer: finally runs, then from try

Hmm, you may be wondering how finally can run if try already returned.

In the above example, you can see that:

  1. When try hits return, JavaScript remembers the return value, but doesn’t leave the function yet.
  2. It runs the finally block first, which prints finally runs.
  3. Only then does the function actually return "from try", and console.log prints it.

So finally really does always run, even after a return.

3. What happens when both try and finally have a return?

Section titled “3. What happens when both try and finally have a return?”
function test() {
    try {
        return "from try";
    } finally {
        return "from finally";
    }
}

console.log(test());

Answer: from finally

In the above example, you can see that:

  1. try wants to return "from try", but finally still has to run first.
  2. finally has its own return, which overrides the one from try.
  3. So the function returns "from finally".

4. Why doesn’t try...catch catch errors inside setTimeout?

Section titled “4. Why doesn’t try...catch catch errors inside setTimeout?”
try {
    setTimeout(() => {
        throw new Error("Late error");
    }, 1000);
} catch (err) {
    console.log("Caught:", err.message);
}

Answer: Nothing is caught. After a second, you get Uncaught Error: Late error.

Wait, what? The throw is clearly inside the try!

In the above example, you can see that:

  1. setTimeout doesn’t run the callback right away. It just schedules it for later.
  2. So the try block finishes almost instantly, and no error has happened yet. catch has nothing to catch.
  3. One second later, the callback runs and throws. But by then, the try...catch is long gone.

try...catch only catches errors that happen while it’s running. The fix is to put the try...catch inside the callback:

setTimeout(() => {
    try {
        throw new Error("Late error");
    } catch (err) {
        console.log("Caught:", err.message); // Caught: Late error
    }
}, 1000);
try {
    try {
        throw new Error("Inner");
    } catch (err) {
        console.log("Inner catch:", err.message);
        throw new Error("Outer");
    } finally {
        console.log("Inner finally");
    }
} catch (err) {
    console.log("Outer catch:", err.message);
}

Answer:

Inner catch: Inner
Inner finally
Outer catch: Outer

In the above example, you can see that:

  1. The inner try throws "Inner", so the inner catch handles it.
  2. The inner catch then throws a new error, "Outer".
  3. Before that error leaves the inner block, the inner finally runs.
  4. The new error then travels up to the outer try, where the outer catch handles it.

6. What are the common error types in JavaScript?

Section titled “6. What are the common error types in JavaScript?”
console.log(userName);   // ReferenceError: userName is not defined
null.length;             // TypeError: Cannot read properties of null
new Array(-1);           // RangeError: Invalid array length
JSON.parse("{bad json}"); // SyntaxError: Expected property name or '}' in JSON

In the above example, you can see that:

  1. ReferenceError: You used a variable that doesn’t exist.
  2. TypeError: You did something a value doesn’t support, like reading a property of null or calling something that isn’t a function.
  3. RangeError: A number is outside the allowed range, like a negative array length or a stack overflow.
  4. SyntaxError: The code (or JSON, in this case) isn’t written correctly.
try {
    let a = ;
} catch (err) {
    console.log("Caught it!");
}

Answer: No. The whole script fails with SyntaxError: Unexpected token ';', and nothing runs at all.

In the above example, you can see that:

  1. Before running any code, JavaScript first reads the whole script to check that it’s written correctly.
  2. let a = ; is broken, so JavaScript refuses to run anything. The try block never even starts.
  3. try...catch can only catch errors that happen while the code is running.

But wait, didn’t we catch a SyntaxError from JSON.parse in the last question? Yes! That’s because the JavaScript code there was fine. The JSON text was broken, and JSON.parse threw the error while it was running.

8. How do you catch only a specific type of error in JavaScript?

Section titled “8. How do you catch only a specific type of error in JavaScript?”
function parseUser(json) {
    try {
        const user = JSON.parse(json);
        return user.name.toUpperCase();
    } catch (err) {
        if (err instanceof SyntaxError) {
            console.log("Invalid JSON, please check the data.");
        } else {
            throw err;
        }
    }
}

parseUser("{bad json}"); // Invalid JSON, please check the data.
parseUser("{}");          // Uncaught TypeError: Cannot read properties of undefined

In the above example, you can see that:

  1. instanceof checks what type of error we got.
  2. If it’s a SyntaxError, we know the JSON was bad, so we handle it with a friendly message.
  3. Anything else, like the TypeError from a missing name, is a bug we didn’t expect. So we rethrow it with throw err.

Interviewers ask this because catching every error and ignoring it hides real bugs. Only handle the errors you expect, and let the rest through.

9. Why should you throw an Error object instead of a string?

Section titled “9. Why should you throw an Error object instead of a string?”
try {
    throw "Something went wrong";
} catch (err) {
    console.log(err.message); // undefined
    console.log(err.stack);   // undefined
}

try {
    throw new Error("Something went wrong");
} catch (err) {
    console.log(err.message); // Something went wrong
    console.log(err.stack);   // Error: Something went wrong at ...
}

In the above example, you can see that:

  1. JavaScript lets you throw anything, even a plain string.
  2. But a string doesn’t have message or stack. Any code that expects them gets undefined.
  3. An Error object gives you the message, plus a stack trace that shows exactly where the error came from.

That stack trace is what saves you hours of debugging, so always throw new Error(...).

You practiced how to:

  • Predict the order in which try, catch and finally run
  • Know what happens when return is used inside try and finally
  • Explain why try...catch can’t catch errors in a setTimeout callback or a syntax error in your code
  • Name the common error types, handle only the ones you expect, and rethrow the rest

Just remember this one rule. try...catch only catches errors that happen while it’s running, and finally always gets the last word.