← All Articles

JavaScript Errors Cheat Sheet: Types, Messages, and Fixes

At a Glance
Red text in the browser consoleUncaught error crashes the pagePromise rejection warnings

The message names the symptom, the stack names the location, and the error type names the family. Read all three before changing code.

The Seven Built-in Error Types

TypeMeaningClassic example
SyntaxErrorCode can't parse — nothing runsUnexpected token '}'
ReferenceErrorIdentifier doesn't exist in scopex is not defined
TypeErrorOperation on wrong typeCannot read properties of undefined
RangeErrorValue out of allowed rangeMaximum call stack size exceeded
URIErrorMalformed URI passed to encode/decodedecodeURIComponent('%')
EvalErrorLegacy, effectively unused—
AggregateErrorMultiple errors as one (Promise.any)errors property holds the list

The Messages You Actually See

Cannot read properties of undefined (reading 'x')

Something is undefined where you expected an object — most often data that hasn't loaded, a typo'd property, or an empty array index. Fixes: optional chaining (obj?.a?.b), default values (const items = data.items ?? []), and guarding before access. Full guide: Cannot read properties of undefined.

x is not a function

You're calling something that isn't callable: a typo (arr.lenght()), a method on an undefined import (imports.foo() where the module exports differently — named vs default), or a variable shadowed by something else. Guide: is not a function.

Maximum call stack size exceeded

Infinite recursion, or a recursive function missing its base case. Common in the wild: a getter that reads itself, a React effect that updates the state it depends on, or JSON.stringify on a circular structure (that one throws a different error but in the same family). Guide: Maximum call stack.

Unexpected token / Invalid or unexpected token

SyntaxError — the parser stopped where the code stops making sense. Read the line and column it names, and check the line before it: a missing bracket, an unclosed string, or a stray character (smart quotes pasted from a document are the classic) all report on the following line. Guide: Unexpected token.

Assignment to constant variable

Writing to a const. Note: mutating contents is allowed (const arr = []; arr.push(1) works) — only rebinding is not.

Cannot access 'x' before initialization

Temporal dead zone: a let/const accessed before its declaration line executes. Usually an import cycle or a function called too early.

Uncaught (in promise) TypeError

An async function threw and nothing handled the rejection. Add .catch() or wrap in try/catch inside the async function; for fire-and-forget calls, at minimum a global handler.

window.addEventListener('unhandledrejection', (e) => {
  report(e.reason)
})

Reading the Stack Properly

The stack tells you the call path, not the cause. Two habits that shorten debugging: (1) click the top frame in your own code — skip node_modules and browser internals; the first frame in your source is the crash site, the next below it is the caller that passed bad data; (2) distinguish async boundaries — frames after await show the resumption point, which is often not where the promise was created. Deeper method: How to read stack traces.

Error Handling Patterns That Scale

  1. Throw Errors, not strings. throw new Error('msg') — strings lose the stack.
  2. Preserve the cause when wrapping: throw new Error('load failed', { cause: err }) (ES2022) keeps the chain.
  3. Custom error classes for catchable domains: class ApiError extends Error { constructor(msg, status) { super(msg); this.status = status } } — and check instanceof ApiError, not message text.
  4. Never swallow silently. An empty catch block is a future incident with no evidence.
  5. One global net per boundary: React error boundary for render, window.onerror/unhandledrejection for the rest, process.on('uncaughtException') on Node (log, then exit).

Related Errors

TypeError: Cannot read properties of undefined · TypeError: is not a function · SyntaxError: Unexpected token