How do you read an error message?
An error line has three parts, always in the same order. First the type, such as TypeError. Then the message, such as Cannot read properties of undefined (reading 'name'). Then the place: the file and line number where JavaScript gave up. The editor's Console shows all three and adds a plain-words explanation underneath.
Read the message slowly, word by word. reading 'name' tells you the code tried to read .name, and of undefined tells you the thing before the dot was undefined. So the question to answer is: on that line, which value before .name was missing? That question is usually faster than guessing at fixes.
The line number points to where the failure surfaced, which is not always where the mistake is. If line 7 reads bird.name and bird is undefined, the real bug may be on line 3, where bird was looked up with the wrong key. Start at the named line and work backwards to where the bad value came from.


Which error types will you see most?
Four types cover nearly everything a beginner meets. Learn what each one usually means and you halve the time spent on a bug.
ReferenceError: a name that no scope declares. Usually a typo (totlfortotal), a variable used outside the block it was declared in, or a variable used before itsletline.TypeError: the value exists but is the wrong kind for what you did with it. Calling something that is not a function, reading a property ofnullorundefined, or assigning to aconst.SyntaxError: the file is not valid JavaScript, so none of it runs. A missing brace, an extra bracket, or a stray character. The line number points to where the parser got confused, often just after the real mistake.RangeError: a number is outside the allowed range, such asnew Array(-1)or(3.14159).toFixed(200). You also see it asMaximum call stack size exceededwhen a function calls itself forever.
What do try, catch and finally do?
Code inside try { } runs normally. If anything inside it throws, JavaScript stops that block at once and jumps to catch (error) { }, handing you the error object. Code after the whole statement then carries on, so one failed step does not stop the rest of the page.
The error object has a name such as "TypeError" and a message with the text. Use error.message when showing something to a visitor, and log the full error for yourself with console.error(error).
A finally { } block runs after try and catch whichever way things went. Use it for clean-up that must always happen: hiding a loading message, re-enabling a button, closing something you opened. The parentheses after catch are optional when you do not need the error, as in catch { }, supported in all current browsers.
const button = document.querySelector("#save");
button.disabled = true;
try {
saveOrder();
} catch (error) {
console.error(error);
showMessage("Saving failed, please try again.");
} finally {
button.disabled = false;
}When should you wrap code in try/catch?
Wrap the code that can fail for reasons outside your control: reading data a visitor typed, parsing JSON from a server, using localStorage (which can be full or blocked), or calling a function that is documented to throw. Those are failures you can plan for and explain.
Do not wrap everything to make red text go away. A ReferenceError from a typo is a bug in your code, and catching it hides the bug instead of fixing it. If the only thing your catch block can do is nothing, you probably should not catch there.
Keep try blocks small. If ten lines sit inside one try, you cannot tell which line failed from the catch block, and you risk catching errors you never meant to handle.
How do you throw your own error with a helpful message?
Use throw new Error("message") when your function receives something it cannot work with. Throwing stops the function immediately and passes the problem up to whoever called it, who can catch it or let it surface in the Console.
Write the message for the person debugging, which is often you next week. Say what was expected and what actually arrived: Order needs a whole number of loaves, got "two" beats Invalid input. Including the bad value saves a round of logging.
Always throw an Error object, not a bare string. throw "bad" works, but a string has no stack trace, no name and no message, so code that reads error.message gets undefined. For specific cases you can throw built-in types too, such as new RangeError("Quantity must be 1 to 20").
function setQuantity(qty) {
if (qty < 1 || qty > 20) {
throw new RangeError(`Quantity must be 1 to 20, got ${qty}`);
}
return qty;
}Why validate input before using it?
Most runtime errors come from a value that is not what the code assumed: an empty form field, a number that arrived as text, an object missing a property. Checking the value at the start of a function, before doing any work, turns a confusing TypeError deep inside into a clear message at the door.
Validation can throw, or it can return early with a friendly result. Throw when the caller made a programming mistake. Return a message, or show one on the page, when a visitor typed something odd, because that is an expected situation and not a bug.
Form values are always strings. "3" + 1 is "31", so convert with Number(value) and then check Number.isNaN or Number.isInteger before trusting the result.
function parseLoaves(text) {
const count = Number(text);
if (!Number.isInteger(count) || count < 1) {
return null;
}
return count;
}
console.log(parseLoaves("3"), parseLoaves("lots"));What happens to errors inside promises?
Code that waits for something, such as fetch, reports failure through a promise instead of throwing on the spot. A plain try/catch around the fetch call does not see that failure, because it arrives later. You handle it with .catch() on the promise, or with try/catch around an await, which the async lessons cover.
If nothing handles a failed promise, the browser logs Uncaught (in promise) with the error. Treat that line like any other uncaught error: find the promise and give it a handler that shows something useful.
fetch("/api/bakery/menu")
.then((response) => response.json())
.then((menu) => console.log(menu))
.catch((error) => console.error("Menu failed:", error.message));Why is swallowing errors silently so harmful?
An empty catch { } makes the Console quiet and the page wrong. The visitor sees a blank space or a stale number, and you get no clue where to look. It is one of the most common patterns in AI-generated code, often written as catch (e) { } or catch (e) { return null; } around a whole function.
At minimum, log the error with console.error so you can see it during development, and show the visitor a short message that says something failed. If you truly expect a failure and want to ignore it, leave a comment saying why, so the next reader knows it was deliberate.
When you review code, search for catch and read every block. Each one should either recover in a way you can describe, report the problem, or rethrow it with throw error; for an outer handler.
Field notes
- An error shows its type, then a message, then the file and line number.
- Code in
tryruns normally, and if it throws,catchreceives the error. - Wrap code that can fail for reasons outside your control, like user input.
- Throw your own error with a clear message when a function gets bad input.
Easy to get wrong
An empty catch hides the failure from both you and the visitor. Log it and tell the visitor something went wrong.
A thrown string has no message, no name and no stack trace, so handlers that read error.message get undefined.
Form values are strings and may be empty. Converting and checking first stops NaN from spreading through every later calculation.
Questions people ask
Why does a SyntaxError stop the whole file?
The browser reads the entire file before running any of it. If it cannot understand the file, it runs nothing. Other errors happen while running, so the lines before them have already run.
Should I catch errors in every function?
No. Catch where you can do something useful: show a message, retry, or use a fallback. Let errors from lower functions travel up to that point.
What is the stack trace?
The list of function calls that led to the error, newest first. In DevTools it appears under the error line and lets you click through to each call site.
Can I rethrow an error after logging it?
Yes. Write throw error; inside the catch block. This is handy when a low-level function wants to log context and still let a higher-level handler decide what the visitor sees.