JavaScript Errors Cheat Sheet: Types, Messages, and Fixes
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
| Type | Meaning | Classic example |
|---|---|---|
| SyntaxError | Code can't parse — nothing runs | Unexpected token '}' |
| ReferenceError | Identifier doesn't exist in scope | x is not defined |
| TypeError | Operation on wrong type | Cannot read properties of undefined |
| RangeError | Value out of allowed range | Maximum call stack size exceeded |
| URIError | Malformed URI passed to encode/decode | decodeURIComponent('%') |
| EvalError | Legacy, effectively unused | — |
| AggregateError | Multiple 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
- Throw Errors, not strings.
throw new Error('msg')— strings lose the stack. - Preserve the cause when wrapping:
throw new Error('load failed', { cause: err })(ES2022) keeps the chain. - Custom error classes for catchable domains:
class ApiError extends Error { constructor(msg, status) { super(msg); this.status = status } }— and checkinstanceof ApiError, not message text. - Never swallow silently. An empty catch block is a future incident with no evidence.
- 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