When JavaScript encounters an error it cannot handle, it prints an error message and a stack trace. The stack trace tells you exactly where the problem is. Learning to read them turns a frustrating debug session into a thirty-second fix.
Anatomy of an error
TypeError: Cannot read properties of undefined (reading 'name')
at displayUser (app.js:15:23)
at loadData (app.js:8:5)
at HTMLButtonElement.<anonymous> (app.js:3:1)
This message has three parts:
- Error type —
TypeError— what kind of error occurred - Message —
Cannot read properties of undefined (reading 'name')— what went wrong - Stack trace — the list of function calls that led to the error
Error types
The most common error types:
| Type | What it means |
|---|---|
| TypeError | A value is not the expected type — calling a method on undefined, passing wrong arguments |
| ReferenceError | A variable is not declared — typo in a variable name, accessing a variable out of scope |
| SyntaxError | The code has invalid syntax — missing bracket, unmatched parenthesis |
| RangeError | A value is outside the valid range — infinite recursion, invalid array length |
| Error | A generic error — usually thrown manually with new Error("...") |
Reading the stack trace
Each line in the stack trace is one function call, listed from most recent to oldest:
at displayUser (app.js:15:23) ← where the error happened
at loadData (app.js:8:5) ← who called displayUser
at HTMLButtonElement.<anonymous> (app.js:3:1) ← the original trigger
The format is:
at functionName (filePath:lineNumber:columnNumber)
The first line is where the error occurred. The lines below show the call chain — how the code got there.
Finding the problem
Start with the first line:
at displayUser (app.js:15:23)
Go to app.js, line 15, column 23. That is the exact position where the error happened.
The message says Cannot read properties of undefined (reading 'name'). So something on line 15 is trying to read .name on undefined:
// app.js line 15
console.log(user.name); // user is undefined
Then trace backward through the stack to find where user should have been set:
at loadData (app.js:8:5)
Line 8 of app.js called displayUser with the bad value.
Common error messages
Cannot read properties of undefined (reading 'x')
You are accessing a property on undefined. Check the value before the dot:
user.name; // user is undefined
Fix by checking for existence or providing a default:
user?.name; // undefined — no error
user && user.name; // undefined — no error
x is not a function
You are trying to call something that is not a function:
const value = "hello";
value.push("!"); // "hello".push is not a function — strings do not have .push()
Cannot set properties of null (setting 'x')
You are trying to set a property on null. Usually happens when a DOM element is not found:
const modal = document.querySelector(".nonexistent");
modal.textContent = "Hello"; // modal is null
Unexpected token
A syntax error — the parser found invalid syntax:
const obj = { name: "Ada", }; // trailing comma in object literal — valid in modern JS
const obj = { name: "Ada" } // missing semicolon if next line starts with (
Maximum call stack size exceeded
Infinite recursion — a function calls itself without a base case:
function factorial(n) {
return n * factorial(n - 1); // no base case — runs until stack overflows
}
Stack traces in async code
Async stack traces include promise and async function frames:
Error: Failed to fetch
at apiRequest (api.js:12:11)
at async loadData (app.js:5:18)
at async HTMLButtonElement.<anonymous> (app.js:2:3)
The async keyword before function names in the stack trace indicates the error occurred inside an async function.
Minified code
In production builds, code is often minified — variable names shortened, whitespace removed, everything in one file. Stack traces in minified code point to positions in the minified file, not your source code:
at n (app.a3f2b.js:1:4823)
Source maps translate these back to your original source. They are generated by build tools and should not be deployed to production for security reasons, but are essential for local debugging.
What to carry forward
- error messages have a type, a description, and a stack trace
- the stack trace lists function calls from most recent to oldest
- the first line is where the error happened; subsequent lines show how the code got there
- go to the file, line number, and column to find the exact problem
- common errors like
undefinedproperty access andnot a functionare quick to fix once you recognize them - minified stack traces require source maps to be readable
Stack traces are your first tool when something goes wrong. The next lesson covers the other tools — console and browser DevTools.