PureDevTools

JavaScript Error Reference

All JavaScript error types — TypeError, ReferenceError, SyntaxError, RangeError, and more — with causes, fixes, and handling patterns

All processing happens in your browser. No data is sent to any server.
9 error types

Browse by Error Type

Your production error tracker shows TypeError: Cannot read properties of undefined (reading 'map') — 500 occurrences this week. Is it a missing API response? A race condition? An optional field? The error message tells you what failed but not why. You need to understand the error type hierarchy, common causes for each type, and the fix patterns — not just the stack trace.

Why This Reference (Not the Error Types Guide)

PureDevTools has two JavaScript error tools. This one is a comprehensive reference with every error type, common error messages, their causes, and fixes — searchable by error message text. The Error Types guide focuses on the type hierarchy and handling patterns. Use this reference when you have a specific error message to diagnose.

What Is a JavaScript Error?

A JavaScript error is an object that describes an exceptional condition — something that went wrong during parsing or execution. When an error is thrown and not caught, execution halts and the error propagates up the call stack. All built-in JavaScript errors are instances of the Error class or one of its subtypes.

Every error object has two key properties:

try {
  null.foo;
} catch (e) {
  console.log(e.name);    // "TypeError"
  console.log(e.message); // "Cannot read properties of null (reading 'foo')"
  console.log(e instanceof TypeError); // true
  console.log(e instanceof Error);     // true
}

Standard JavaScript Error Types

TypeError

TypeError is the most common runtime error. It occurs when an operation receives a value of the wrong type — most frequently accessing a property on null or undefined, or calling a non-function.

// Accessing property on undefined:
const user = undefined;
user.name; // TypeError: Cannot read properties of undefined (reading 'name')

// Calling a non-function:
const x = 42;
x(); // TypeError: x is not a function

// Safe access with optional chaining:
const name = user?.name ?? "Anonymous"; // No error

ReferenceError

ReferenceError occurs when you reference an identifier that has never been declared in scope, or when you access a let/const variable before its initialization (the Temporal Dead Zone).

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

console.log(count); // ReferenceError: Cannot access 'count' before initialization
let count = 0;

// var is different — it is hoisted and initialized to undefined:
console.log(x); // undefined (no error)
var x = 5;

SyntaxError

SyntaxError is thrown when JavaScript cannot parse the code. At the script level, it halts the entire script before a single line runs. At runtime, it appears when JSON.parse() receives malformed input.

// Invalid JSON (most common runtime case):
JSON.parse("{ name: 'Alice' }");
// SyntaxError: Expected property name or '}' in JSON at position 2

// Correct JSON requires double quotes:
JSON.parse('{ "name": "Alice" }'); // OK

// Always wrap JSON.parse in try/catch:
try {
  const data = JSON.parse(rawString);
} catch (e) {
  console.error("Invalid JSON:", e.message);
}

RangeError

RangeError is thrown when a numeric value falls outside its allowed range. The most dramatic case is stack overflow from unbounded recursion.

// Infinite recursion:
function recurse() { return recurse(); }
recurse(); // RangeError: Maximum call stack size exceeded

// Invalid array length:
new Array(-1); // RangeError: Invalid array length

// Number formatting out of range:
(3.14).toFixed(200); // RangeError: toFixed() digits must be 0–100

URIError

URIError is thrown by URI encoding/decoding functions when they receive a malformed string. Most commonly encountered when decodeURIComponent() receives an invalid percent-encoding.

decodeURIComponent("%"); // URIError: URI malformed
decodeURIComponent("%GG"); // URIError: URI malformed

// Always wrap in try/catch for user-supplied URLs:
try {
  const decoded = decodeURIComponent(userInput);
} catch (e) {
  if (e instanceof URIError) {
    console.error("Invalid URL encoding");
  }
}

EvalError

EvalError is a historical error type that modern JavaScript engines no longer throw. It was originally thrown for misuse of eval(). Today, eval() misuse results in TypeError or SyntaxError. EvalError is preserved for backwards compatibility and can be caught in legacy codebases.

AggregateError

AggregateError groups multiple errors into one. Introduced in ES2021, it is thrown by Promise.any() when all promises reject. Access individual errors via the .errors array property.

try {
  const result = await Promise.any([
    fetch("/mirror-1/data"),
    fetch("/mirror-2/data"),
    fetch("/mirror-3/data"),
  ]);
} catch (e) {
  if (e instanceof AggregateError) {
    console.log("All mirrors failed:");
    e.errors.forEach(err => console.error("-", err.message));
  }
}

InternalError

InternalError is a non-standard Firefox-only error indicating an internal engine limit was hit — usually too much recursion. Not available in Chrome, Node.js, or Safari. In other engines, the equivalent is RangeError: Maximum call stack size exceeded.

Error Handling Best Practices

Always Specify the Error Type in catch

Catch and re-throw: handle only the errors you expect, and re-throw the rest. This prevents accidentally swallowing unexpected errors.

function parseUserConfig(raw) {
  try {
    return JSON.parse(raw);
  } catch (e) {
    if (e instanceof SyntaxError) {
      throw new Error(`Invalid config format: ${e.message}`);
    }
    throw e; // Re-throw unexpected errors
  }
}

Use the Error Cause Chain (ES2022)

The cause option links errors together, preserving the original error while adding context.

async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    return await res.json();
  } catch (e) {
    throw new Error(`Failed to load user ${id}`, { cause: e });
  }
}

// Access the original error:
try {
  await loadUser(42);
} catch (e) {
  console.error(e.message);       // "Failed to load user 42"
  console.error(e.cause.message); // Original network/parse error
}

Create Custom Error Classes

Use custom error classes to add structured context and enable precise instanceof checks.

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

function validateEmail(email) {
  if (!email.includes("@")) {
    throw new ValidationError("Invalid email address", "email");
  }
}

try {
  validateEmail("not-an-email");
} catch (e) {
  if (e instanceof ValidationError) {
    highlightField(e.field);
    showError(e.message);
  }
}

Handle Unhandled Promise Rejections

Async errors that are not caught with try/catch or .catch() become unhandled rejections. Set up a global handler to catch them:

// Browser:
window.addEventListener("unhandledrejection", (event) => {
  console.error("Unhandled rejection:", event.reason);
  event.preventDefault(); // Suppress console warning if handled
});

// Node.js:
process.on("unhandledRejection", (reason) => {
  console.error("Unhandled rejection:", reason);
  process.exit(1);
});

Frequently Asked Questions

What is the difference between TypeError and ReferenceError?

A ReferenceError means the identifier does not exist at all — the variable was never declared. A TypeError means the identifier exists but the value it holds is of the wrong type for the operation you are performing. For example: foo() throws ReferenceError if foo was never declared, but TypeError if foo is declared but holds a string instead of a function.

Why does accessing a property on undefined throw TypeError but on an undeclared variable throw ReferenceError?

undefined is a value — the variable exists and holds undefined. Accessing .property on a value of type undefined is a type mismatch, hence TypeError. An undeclared variable does not exist in the scope chain at all, so looking it up throws ReferenceError.

What is the Temporal Dead Zone (TDZ)?

The TDZ is the period between the start of a block scope and the point where a let or const variable is initialized. During this period, the variable exists (it is hoisted) but accessing it throws ReferenceError: Cannot access 'x' before initialization. var declarations do not have a TDZ — they are hoisted and initialized to undefined.

How do I safely catch errors without knowing the type?

Use instanceof to check for specific types before accessing type-specific properties. For completely unknown errors (anything could be thrown, including non-Error objects), check with instanceof Error first:

catch (e) {
  if (e instanceof TypeError) { /* ... */ }
  else if (e instanceof RangeError) { /* ... */ }
  else if (e instanceof Error) {
    // Generic error handling
    console.error(e.message);
  } else {
    // Someone threw a non-Error (string, number, etc.)
    console.error("Unknown error:", e);
  }
}

How do I log the full stack trace of an error?

Use console.error(err) which automatically formats the stack, or console.error(err.stack) for the raw string. In production, send err.stack to your error tracking service alongside err.message and err.name.

Is my data private?

Yes. All processing happens entirely in your browser. No content is sent to any server.

Related Tools

More JavaScript Tools