JavaScript Tutorial · JavaScript Toolbox · Lesson 35 of 44

JavaScript Errors

Handle errors with try, catch and finally, and throw your own.

try...catch...finally

When code inside try throws, execution jumps to catch. finally runs whether or not there was an error — use it for cleanup:

Example 1Try it yourself
try {
  const user = null;
  console.log(user.name);
} catch (err) {
  console.log(err.name + ":", err.message.includes("null") ? "can't read a property of null" : err.message);
} finally {
  console.log("cleanup runs either way");
}

Output

TypeError: can't read a property of null
cleanup runs either way

Throwing errors

throw an Error (not a plain string) so you get a message and a stack trace. Built-in types include TypeError, RangeError and SyntaxError.

Custom errors

Extend Error to create error types your code can recognise:

Example 2Try it yourself
class ValidationError extends Error {
  constructor(field, message) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

function register(email) {
  if (!email.includes("@")) throw new ValidationError("email", "Email is invalid");
  return "registered";
}

for (const email of ["[email protected]", "nope"]) {
  try {
    console.log(register(email));
  } catch (err) {
    if (err instanceof ValidationError) {
      console.log(`${err.name} on ${err.field}: ${err.message}`);
    } else {
      throw err;
    }
  }
}

Output

registered
ValidationError on email: Email is invalid

Only catch errors you can handle meaningfully. Swallowing every error with an empty catch {} hides bugs.

Test yourself

Which block runs whether or not an error was thrown?

  1. catch
  2. finally
  3. else
  4. always
Show answer

Answer: finally