JAVASCRIPT / GETTING STARTED
Reading an error message in the console
Split any red console error into its name, message, and stack trace, and use each part to decide what broke and which line to open first.
What you will learn
- Split a console error into name, message, and stack before you change any code.
- Tell ReferenceError (no such name) from TypeError (name found, value can't do it).
- Read a stack top-down: the top frame threw it, the frames under it are the callers.
- Spot a SyntaxError by the missing output above it: nothing in the file ran.
Understanding Reading an error message in the console
A red line in the console is not free-form prose written for you; it is an Error object printed out. Everything before the colon is that object's name property, everything after the colon is its message, and the indented lines underneath come from its stack property. You can confirm this by catching the error and logging those properties yourself, which is what the first example does. Keeping the three pieces separate is the entire skill, because each answers a different question: what kind of failure, which value was involved, and where execution was standing when it happened.
The name narrows the failure to a category, and the categories describe genuinely different bugs. ReferenceError means the engine looked up an identifier and found no binding for it in any enclosing scope, which is nearly always a typo or a name used before it was declared. TypeError means the lookup succeeded but the value cannot do what the code asked of it: reading a property of undefined or null, or calling something that is not a function. SyntaxError is different in kind, because the engine could not parse the source at all, so no statement in that file ran.
The indented lines under the message are the call stack at the instant of the throw, innermost call first. The top frame is where the operation failed, which is often not where the mistake was made: a function that receives a bad argument is the one that throws, while the caller that built that argument sits one frame lower. So read the top frame to see what broke, then walk downwards until you reach the frame that produced the wrong value. The file:line:column at the end of each frame is clickable in DevTools and puts the cursor on that exact character.
const user = { name: "Ada" };
console.log("before the error");
try {
console.log(user.profile.age);
} catch (err) {
console.log("name:", err.name);
console.log("message:", err.message);
console.log("is TypeError:", err instanceof TypeError);
}
console.log("after the catch");A console error carries three separate signals — the error name, the engine's message about a specific value, and the call stack to the throw site — and each one tells you something different.
Worked examples
ReferenceError names the identifier it could not resolve
Shows that the message quotes the misspelled name, which makes it a ready-made search term.
function greet(name) {
return "Hello, " + nam;
}
try {
greet("Ada");
} catch (err) {
console.log(err.name + ": " + err.message);
}Example explained
Line 1nam is a typo for the parameter name, so no binding for it exists in any scope.
Line 2The engine reports the name it failed to resolve, so the message quotes the misspelling, not the correct name.
Line 3The string concatenation never happens: the failed lookup throws before the + operator runs.
The top stack frame is not always the buggy line
Reads the stack string directly to show that the throw site and the source of the bad value are different frames.
function readAge(person) {
return person.age.toFixed(0);
}
function showAge(person) {
console.log(readAge(person));
}
try {
showAge({ name: "Ada" });
} catch (err) {
const frames = err.stack.split("\n").filter(line => line.includes("at "));
console.log("message:", err.message);
console.log("innermost frame:", frames[0].trim().startsWith("at readAge"));
console.log("its caller:", frames[1].trim().startsWith("at showAge"));
}Example explained
Line 1person.age is undefined because the object has only a name, so reading toFixed on it throws inside readAge.
Line 2err.stack is a single string: one message line followed by one line per frame, which is why splitting on newlines works.
Line 3frames[0] is readAge and frames[1] is showAge, confirming that the list runs from innermost call outwards.
Line 4The object missing its age was built two frames down, in the try block, and that is where the real fix belongs.
A SyntaxError happens before anything runs
Uses new Function to compile a broken string so a parse failure can be observed inside a running program.
console.log("statement 1 ran");
try {
new Function("let total = ;");
} catch (err) {
console.log("caught:", err.name);
console.log("is SyntaxError:", err instanceof SyntaxError);
}
console.log("statement 3 ran");Example explained
Line 1new Function compiles the string it is given, so the parse failure occurs at that call and can be caught.
Line 2The name is SyntaxError, the class the engine uses for source it cannot parse into code.
Line 3The surrounding logs still print because only the compiled string failed to parse.
Line 4Had that broken line been in the file itself, statement 1 would never have printed either, which is the tell-tale sign in a real console.
Important notes
Messages are engine prose and differ: Chrome and Node say "Cannot read properties of undefined (reading 'age')" where Firefox says "user.profile is undefined". The name values are standardised, but the exact wording and the stack string format are not, so never match on message text in code.
An uncaught error only unwinds the call stack it happened in. Later timers, event handlers, and promise callbacks still run, so a page can look half-working with just one red line in the console.
Common mistakes
Reading "x is not defined" as "x is undefined": the first means no binding exists and declaring x fixes it, the second means x exists and holds undefined, where declaring it again changes nothing.
Patching the top stack frame, for example adding ?. to silence "Cannot read properties of undefined", which lets the undefined value keep travelling and moves the crash further from its cause.
Trusting the line number on a SyntaxError: the parser reports where it gave up, so a brace left unclosed on line 12 is often flagged at the very last line of the file.
Try it yourself
Change, predict, then run
Before pressing Enter, write down which error name you expect and which property name you think the message will quote. Then run const cart = { items: [] }; console.log(cart.total.toFixed(2)); in the console, compare it with your prediction, and change the object so the line prints 0.00.
Open the JavaScript workspaceCheck your understanding
A script produces no console output at all, and the console shows one red line: SyntaxError: Unexpected end of input, pointing at the file's last line. What does the total absence of your own logs tell you?
- The logs did print but were cleared from the console when the error was reported.
- No statement was executed because parsing failed, so an unclosed brace or bracket sits somewhere earlier in the file.
- The first console.log threw, so the bug is in the value being logged.
- Execution reached the last line and stopped there, so the mistake is on the last line.
Show answer
The engine parses a whole file before running any of it, so a SyntaxError means zero statements executed, which is exactly why no logs appeared. Option 3 is tempting because the error points at the last line, but "Unexpected end of input" means the parser hit the end of the file while still waiting for a closing token, so the opener it is missing is earlier in the source.