By the end of this lesson, you will be able to read JavaScript error messages and stack traces to find the likely source of a bug.
What it is
Debugging errors in JavaScript means using the information the runtime gives you when code fails. An error message tells you what kind of problem occurred, such as TypeError, ReferenceError, or SyntaxError. A stack trace is the list of function calls that led to the error. It is usually printed from the innermost call outward, so you read it top-down: the first line is the error, the next lines show where it happened and which functions called it.
Related terms include throw, catch, call stack, source location, and source maps.
Why it matters
- It turns a vague failure into a specific file, line, and column.
- It helps you separate the place where bad data entered from the place where the code finally crashed.
- It reduces guesswork when fixing asynchronous code, event handlers, or library errors.
- It makes bug reports clearer because you can include the exact error and stack trace.
Syntax or steps
- Reproduce the error and copy the full message and stack trace.
- Read the first line to identify the error type and message.
- Look at the top stack frame for the file, line, and column where the error was thrown.
- Read downward to see which functions called that code.
- Check the values used in the top frame, then trace backward to find where they became invalid.
Example
function parseUser(input) {
const data = JSON.parse(input);
return data.name.toUpperCase();
}
function handleRequest(body) {
return parseUser(body);
}
try {
handleRequest('{"name": 42}');
} catch (error) {
console.error(error.stack);
}
A typical stack trace might look like this:
TypeError: data.name.toUpperCase is not a function
at parseUser (app.js:3:21)
at handleRequest (app.js:7:10)
at <anonymous> (app.js:11:3)
Part by part:
TypeError: data.name.toUpperCase is not a functionsays the value atdata.nameis not a string.at parseUser (app.js:3:21)is the top frame: the failing call is on line 3, column 21.at handleRequest (app.js:7:10)shows thatparseUserwas called fromhandleRequest.- The lower frames are callers, not necessarily the root cause. Here, the root cause is the input passed to
handleRequest.
Common mistakes
- Fixing only the top line. If the top frame crashes because a value is
undefined, the real bug may be earlier. Trace the value backward. - Ignoring the error type. A
SyntaxErroroften means malformed code or JSON, while aReferenceErroroften means a missing variable. - Reading the stack bottom-up. The top frame is usually where the exception was thrown; lower frames show how execution reached it.
- Using a minified stack trace without source maps. If file names look like
bundle.min.js, enable source maps or debug the unminified build.
When to use it
Use stack traces when an error has already occurred and you need to locate it. Use logging or breakpoints when you need to inspect values before a crash.
| Technique | Best for | Limits |
|---|---|---|
| Stack trace | Finding where an exception was thrown and the call chain that caused it. | Does not always show why a value became invalid. |
console.log | Quick checks of values in simple code. | Can be noisy and may miss the exact failing state. |
| Debugger breakpoints | Step-by-step inspection of variables and control flow. | Slower to set up for production issues. |
Practice
Guided exercise: create a function that reads user.email.split("@"), then call it with an object where email is undefined. Read the stack trace and identify the top frame.
Challenge: wrap the call in try...catch and log error.message and error.stack. Expected output should mention Cannot read properties of undefined or a similar message depending on the JavaScript engine.
Quick check
Question: In a JavaScript stack trace, which frame usually shows where the error was thrown?
Answer: The top frame, just below the error message.
Summary
JavaScript stack traces are a map from the crash point back through the calls that led there. Read the error type first, then the top frame, then trace downward to find the invalid input or missing state. This habit turns random failures into targeted fixes.