JavaScript Errors

Errors in JavaScript fall into two categories: errors that happen at parse time (before the code runs) and errors that happen at runtime (while the code is running). This page covers both, along with how to handle them gracefully.

Common error types

SyntaxError

A SyntaxError happens when JavaScript cannot parse your code. It usually means a typo, a missing bracket, or invalid syntax.

// Missing closing parenthesis
console.log('hello';

To fix: check that all brackets, braces, and parentheses are opened and closed correctly.

ReferenceError

A ReferenceError happens when you try to use a variable that does not exist.

console.log(myVariable); // ReferenceError: myVariable is not defined

To fix: check that the variable is declared and that you are not misspelling the name.

TypeError

A TypeError happens when you try to perform an operation on a value of the wrong type.

const name = null;
console.log(name.toUpperCase()); // TypeError: Cannot read properties of null

To fix: check what type of value you are working with before calling methods on it.

RangeError

A RangeError happens when a value is outside the allowed range.

new Array(-1); // RangeError: Invalid array length
(1.2345).toFixed(200); // RangeError: toFixed() digits argument must be between 0 and 100

URIError

A URIError happens when you pass a malformed URI to decodeURI() or decodeURIComponent().

decodeURI('%'); // URIError: URI malformed

Reading error messages

When an error occurs, the console shows you three things:

  1. The file and line number where the error happened.
  2. The type of error.
  3. A description of the error.
app.js:5
if (num > total;) {
                ^

SyntaxError: Unexpected token ';'

Here the error is in app.js at line 5, it is a SyntaxError, and the description tells you exactly what went wrong.

Debugging tips

  • Run your code and read the error message before guessing at the problem.
  • Use console.log() to inspect values at different points if the error is not obvious.
  • Check MDN Web Docs for detailed explanations of specific JavaScript errors.
  • Stack Overflow is useful for common errors; search the exact error message.

Constructing and throwing errors

You can create an error object with new Error() and throw it with the throw keyword.

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

console.log(divide(10, 2)); // 5
console.log(divide(10, 0)); // throws Error: Cannot divide by zero

throw stops execution immediately. Nothing after a throw runs unless the error is caught.

try/catch

Use try/catch to handle errors without crashing the program.

try {
  const result = divide(10, 0);
  console.log(result);
} catch (err) {
  console.error('Something went wrong:', err.message);
}
// Prints: Something went wrong: Cannot divide by zero
// Execution continues here

The code in the try block runs normally. If an error is thrown, execution jumps to the catch block. Code after the try/catch continues running.

finally

The finally block always runs, whether the try succeeded or the catch ran.

async function loadData() {
  showLoadingSpinner();
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`Server error: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (err) {
    console.error('Failed to load data:', err.message);
  } finally {
    // always runs, hides the spinner whether we succeeded or failed
    hideLoadingSpinner();
  }
}

Use finally for cleanup that must happen regardless of the outcome, like hiding a loading indicator or closing a database connection.

Custom error classes

You can extend the built-in Error class to create your own error types. This makes it easier to handle different kinds of errors differently.

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

function validateEmail(email) {
  if (!email.includes('@')) {
    throw new ValidationError('email', 'Email address is not valid');
  }
}

try {
  validateEmail('not-an-email');
} catch (err) {
  if (err instanceof ValidationError) {
    console.error(`Field "${err.field}" failed: ${err.message}`);
  } else {
    throw err; // re-throw unexpected errors
  }
}
// Prints: Field "email" failed: Email address is not valid

Custom error classes let you check the type of error with instanceof and attach extra information (like which field failed).