1.An error message is a clue
When you start writing code, red errors appear often. The same goes for professional developers. The difference is whether you panic when you see an error or read it as a clue. Finding and fixing errors is called debugging, and the first step is to read the message all the way to the end, word by word. The message usually contains the very name of the thing you need to fix.
A JavaScript error message has the shape ErrorName: description. For example, TypeError: Cannot read properties of undefined (reading 'length') means 'the kind is TypeError (the kind of value is wrong), and what happened is that we tried to read length from undefined'. For errors that happen while the code is running, this playground also shows which line the error happened on. That line is your starting point.
Two things are worth knowing. First, the description wording differs slightly between browsers. The messages in this lesson are the wording of V8, the engine used by Chrome-based browsers; other browsers may describe the same error in different words. The error name (TypeError and so on) is fixed by the language rules, so it is mostly the same in every browser. Second, the line where the error happened may not be the line with the mistake. It is common for a value to be made wrongly higher up and to blow up further down, where it is used.
When an error happens, execution stops at that line. So a console.log before the error is printed and one after it is not. This behaviour is a clue that tells you 'how far things ran correctly'. The code below prints the first line and then stops at line 3.
words[2] is an empty slot, so it is undefinedconst words = ["apple", "pear"];
console.log(words[0].length);
console.log(words[2].length);
console.log("This line never runs");5
TypeError: Cannot read properties of undefined (reading 'length')- Error name — what kind of problem is it (
SyntaxError,ReferenceError,TypeError,RangeError…) - Description — what was being done when it got stuck (which name, which property)
- Line number — where it stopped (the mistake may be above it)
2.`SyntaxError` — code that doesn't run at all
A SyntaxError is a grammar error. It happens when the code can't be read as JavaScript — for example when you didn't close a bracket, left out a comma or declared the same name twice. Unlike other errors, it is caught at the reading stage, before the code runs, so not a single line is executed. If even a console.log at the very top prints nothing, suspect a syntax error first.
For syntax errors, this playground shows only the message, without a line number. That makes the clues in the message even more important. missing ) after argument list means the closing bracket of a function call is missing, and Unexpected identifier 'price' means 'price appeared where it shouldn't', in other words something like a comma is missing just before it. When you see Unexpected token, look at the part right before that character. If a name is shown in quotes, searching for that name is a fast way to find the spot.
Syntax errors usually come from things that don't pair up. Check that every opening bracket, curly brace and quote has its closing partner; lining up the indentation makes a broken pair stand out. An editor that highlights matching brackets also helps a lot. Instead of writing long code in one go, write and run a few lines at a time — then when a syntax error appears, you only need to look at the few lines you just wrote.
console.log("hello";SyntaxError: missing ) after argument listprice — the comma at the end of the line above is missingconst item = {
name: "apple"
price: 1500
};SyntaxError: Unexpected identifier 'price'let count = 0;
let count = 1;SyntaxError: Identifier 'count' has already been declaredJSON.parse is also named SyntaxError. But here it is not the code's grammar that is wrong but the 'grammar of the data', and because it happens while running, it comes with a line number. To see whether JSON is broken, paste it into a JSON formatter and it shows right away where it goes wrong.3.`ReferenceError` — no such name
A ReferenceError means 'that name can't be found'. The most common cause is a typo. If you write console as Console or total as totla, JavaScript tells you there is no variable with that name. Upper- and lowercase count as different names. Copy the name that appears before is not defined in the message and search for it in your code, and the place where the spelling differs soon shows up.
The second cause is 'using it before declaring it'. Using a variable made with let or const above the line where it is declared gives Cannot access 'price' before initialization. The third is scope. As we saw in Lesson 5, a variable made inside a function or a { } block can't be seen outside it. Trying to use a variable made inside a loop after the loop has finished gives is not defined.
In code running in strict mode, as in this playground, assigning a value to a name you have never declared, without let or const, is also a ReferenceError. Outside strict mode, this mistake silently creates a new global variable and turns into a bug that is even harder to find; strict mode reports it as an error straight away.
const total = 100;
console.log(totla);ReferenceError: totla is not definedconsole.log(price);
const price = 1500;ReferenceError: Cannot access 'price' before initializationfor (let i = 0; i < 3; i++) {
const last = i;
}
console.log(last);ReferenceError: last is not defined4.`TypeError` — something that value can't do
A TypeError means you asked a value to do something that doesn't fit its kind, and it is the error beginners meet most. The classic one is Cannot read properties of undefined (reading '…'). undefined and null have no properties, yet you put a dot (.) after one to take something out. The name in the brackets is the property you tried to read, and the value just to the left of that dot was undefined.
What matters is 'why did that value become undefined?'. When you read an array slot that doesn't exist (arr[5]) or a property that doesn't exist (user.nmae), JavaScript doesn't throw an error; it quietly returns undefined. The error only comes the moment that undefined is used once more. So print the value to the left of the dot on the error line with console.log, and trace upward to where it came from. The culprit is usually an index out of range, a typo in a property name, or a function that forgot return and so returned undefined.
Another one you will see often is … is not a function. It means you called something that isn't a function with brackets () — either a typo in a method name (toUppercase) or calling a method on the wrong kind of value. For example, toFixed is a number method, so calling it on the string "1500" gives this error. This ties back to the type conversion problems from Lesson 2. Assigning a new value to a variable made with const, which gives Assignment to constant variable., is also a TypeError.
undefined — the error comes after thatconst user = { name: "Alex" };
console.log(user.nmae);
console.log(user.nmae.length);undefined
TypeError: Cannot read properties of undefined (reading 'length')const s = "hello";
console.log(s.toUppercase());TypeError: s.toUppercase is not a functiontoFixedconst price = "1500";
console.log(typeof price);
console.log(price.toFixed(0));string
TypeError: price.toFixed is not a function| Error name | Meaning | Common message | Look here first |
|---|---|---|---|
SyntaxError | can't be read as code | missing ) after argument list | pairs of brackets, commas and quotes |
ReferenceError | no such name | x is not defined | spelling, case, where it is declared, scope |
TypeError | something that value can't do | Cannot read properties of undefined | where the value left of the dot came from |
RangeError | value is outside the allowed range | Maximum call stack size exceeded | negative or huge numbers, recursion that never ends |
5.`RangeError`, and bugs that give no error
A RangeError means the kind of value is right but it is out of range. You get one by giving a negative count, as in "*".repeat(-1), or a negative length, as in new Array(-1). When a function calls itself endlessly you get Maximum call stack size exceeded, which in Chrome-based browsers (V8) is also a RangeError (Firefox reports the same situation as InternalError: too much recursion). Recursion, where a function calls itself, must always have a condition that makes it stop.
Trickier are bugs that produce no error at all: the code runs to the end but the result is wrong. The off-by-one from Lesson 4 is the classic case. Looping with i <= arr.length reads a slot that doesn't exist at the end and adds undefined, and adding undefined to a number gives NaN instead of an error. Dividing by 0 gives Infinity, and 0 / 0 gives NaN — again, no error. If you see NaN, undefined or Infinity in a result, it is a bug signal even without an error message.
A loop that never ends doesn't give an error message either. If the condition of a while is true forever, the program just keeps running. This playground force-stops code that doesn't finish within 2 seconds and tells you it hit the time limit. When you see that notice, suspect the loop's end condition. Check whether the variable used in the condition actually changes inside the loop, and whether it changes in the direction that brings it closer to the end. Running an infinite loop in a real browser tab can freeze the tab, so when you first write a loop, test it with small inputs.
function stars(n) {
return "*".repeat(n);
}
console.log(stars(3));
console.log(stars(-1));***
RangeError: Invalid count value: -1NaN with no error — an off-by-oneconst nums = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= nums.length; i++) {
sum += nums[i];
}
console.log(sum);
console.log(10 / 0, 0 / 0);NaN Infinity NaN
6.The order of debugging — print, hypothesise, shrink
Debugging has a set order. First, write down 'the result I expected' and 'the result I got' in one sentence each. Next, form one hypothesis about the cause (for example: the loop runs one time too many) and run the smallest experiment that can check it. If the hypothesis is right, fix it; if it is wrong, cross it out and move on to the next one. If you change several places at once, you can't tell which change fixed it, so change only one thing at a time.
The handiest experiment tool is console.log. Printing the value at a suspicious spot shows where 'the value in my head' and 'the actual value' start to part ways. Inside a loop, print the index together with the value, and add a label next to the value (console.log("i:", i)) so you don't get confused when the output gets mixed. Printing typeof as well lets you tell apart values that look the same, like "1500" (a string) and 1500 (a number). Once you've found the problem, remove the checking output.
When the code is long, build a minimal reproduction. While keeping the bug appearing, delete unrelated lines one by one until only the shortest code that causes the problem is left. The cause often becomes visible while you shrink it, and when you ask someone else or an AI, short code gets a much more accurate answer. Since explaining often reveals the answer, explaining your code out loud, line by line, is also a widely used method (rubber duck debugging).
NaN. How do you find the cause?const sales = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= sales.length; i++) {
console.log("i:", i, "value:", sales[i]);
sum += sales[i];
}
console.log(sum / sales.length);i: 0 value: 10 i: 1 value: 20 i: 2 value: 30 i: 3 value: undefined NaN
- Step 1 Write down expected and actual. Expected: 20, actual:
NaN. There is no error message, so it is a wrong-result bug. - Step 2 Hypothesis: 'something that isn't a number is mixed into the values being added'. Print
iandsales[i]inside the loop. - Step 3 The output shows that when
i: 3, the value isundefined. The array has only slots 0–2, but the loop went up to 3. - Step 4 Change the condition
i <= sales.lengthtoi < sales.length, and also test an empty array and a one-item array.
undefined. Changing it to < gives 20.7.What to give an AI when you ask about an error
An AI coding assistant is quite useful for explaining error messages and suggesting a direction for the fix. But it is only as accurate as the information it gets. Rather than 'it doesn't work, fix it', give it the full error message, the minimal code that shows the problem, the expected and actual results, the environment (browser, engine) and what you've already tried, and the answer will be far more accurate. Don't summarise the error message — copy and paste it exactly. Translating or shortening it loses key clues (names, properties, line numbers).
There are also things you must strip out before pasting. Passwords, API keys, access tokens and personal information such as real customers' names and phone numbers must be removed and replaced with fake values, even if they are mixed into the code or data. If it is code from your company or school, first check their policy on whether you may paste it into an outside AI. Lesson 10 covers this in more detail.
When you get code fixed by an AI, don't trust it as is — check it. Run it yourself and see whether the original error is gone, whether you get the expected result, and whether it is still right for edge cases like an empty array or 0. AI sometimes gives explanations that sound plausible but are wrong, and sometimes 'fixes' things in a way that only hides the error (for example, always turning the problem value into 0). Ask it to explain why it made the change, and check whether that explanation fits the error message.
- The full error message (name, description, line number) — copied exactly
- The shortest code that shows the problem (minimal reproduction)
- The expected result and the actual result
- The environment (which browser, whether it is this playground, etc.) and what you've already tried
- Passwords, keys and real personal information removed and replaced with fake values
📌 Key points
- Read an error message as 'name: description' plus a line number — the wording differs a little between browsers, but the name is the same
- A
SyntaxErroris caught before running so not one line runs; aReferenceErroris a name problem, aTypeErrora value-kind problem and aRangeErrora range problem undefinedappears quietly and blows up later — trace back where the value to the left of the dot on the error line came fromNaN,Infinityand loops that never end are bug signals that come without an error message — the playground stops execution after 2 seconds- Write down expected and actual → one hypothesis → check it with
console.log→ minimal reproduction; and give an AI the full message and short code, without secrets
🧪 Code lab
Every starter has one bug hidden in it. Run it as is first, read the error message or the wrong result, find the cause and fix just one spot to pass the tests.
Your code runs only inside an isolated sandbox in this browser and is never sent to a server. It has no network access and is stopped after 2 seconds. Edited code is saved only in this browser. Ctrl+Enter (⌘+Enter) runs it; Tab inserts two spaces (press Esc, then Tab, to move on).
JavaScript is off, so the code can't run here, but you can still read each task, its starter code, the automatic checks and a sample solution.
1Fixing a typo in a name
discount(price, rate) takes a price price and a discount rate rate (for example 0.1 is 10%) and returns the discounted price. Running it gives a ReferenceError. Look at the name in the message and fix it.
discount(10000, 0.1)expected9000discount(5000, 0.5)expected2500discount(3000, 0)expected3000discount(0, 0.2)expected0
💡 Hint
prise is not defined — find where that name is and compare it with the parameter names.
Show a sample solution
function discount(price, rate) {
const off = price * rate;
return price - off;
}2Fixing a method that doesn't exist
shout(s) turns the string s into all capitals, adds "!" to the end and returns it. Running it gives TypeError: s.toUppercase is not a function. Find the cause and fix it. For an empty string it returns "!".
shout("hi")expected"HI!"shout("Hello World")expected"HELLO WORLD!"shout("123")expected"123!"shout("")expected"!"
💡 Hint
JavaScript names are case-sensitive. Compare the spelling of the method name you used in Lesson 7 letter by letter.
Show a sample solution
function shout(s) {
return s.toUpperCase() + "!";
}3Fixing an average that gives NaN
average(nums) returns the average of the number array nums. For an empty array it returns 0. There is no error, but the result is NaN. Print i and nums[i] inside the loop and find the cause.
average([10,20,30])expected20average([7])expected7average([1,2])expected1.5average([-5,5])expected0average([])expected0
💡 Hint
Put console.log("i:", i, nums[i]); inside the loop. What is the last value printed?
Show a sample solution
function average(nums) {
if (nums.length === 0) return 0;
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum / nums.length;
}4Fixing a loop that never ends
countDown(n) takes a positive integer n and returns an array counting down from n to 1. Example: countDown(3) → [3, 2, 1], countDown(0) → []. The starter never finishes, so the playground stops it after 2 seconds. Look at the loop's end condition and fix it.
countDown(3)expected[3,2,1]countDown(1)expected[1]countDown(5)expected[5,4,3,2,1]countDown(0)expected[]
💡 Hint
For the condition n > 0 to become false at some point, how must n change inside the loop?
Show a sample solution
function countDown(n) {
const out = [];
while (n > 0) {
out.push(n);
n--;
}
return out;
}🤖 Try asking AI like this
Copy a prompt and replace the [ ] parts with your own situation. Don't take the answer on trust — check it against this lesson.
When you don't know what an error message means
I ran JavaScript in [browser/playground] and got this error: [the full error message, exactly as shown]. Here is the code that causes it: [minimal code]. Explain in plain words what this error means, and tell me, in order of likelihood, which value on which line of my code is probably the cause. Before giving me the answer directly, first tell me where I should check with `console.log`.
When there's no error but the result is wrong
The following function runs without errors but gives the wrong result. Input: [input], expected result: [expected], actual result: [actual]. Code: [minimal code]. Come up with 2–3 hypotheses about the cause and tell me where to put `console.log` to check each one. When you give me fixed code, also tell me what you changed and why, and include edge-case tests (empty array, 0).
When you want to verify code an AI fixed for you
I want to check whether the code you fixed really solves the original problem. Original error: [message], fixed code: [code]. Explain the reason for every changed line, and check for yourself that the fix doesn't just hide the error (for example, by always turning a value into 0). Also give me 3 inputs where this code could fail.
🧰 Related tools
Tools for checking and tidying the JSON, regular expressions and text from this lesson. Don't paste real personal data or passwords.
- JSON FormatterWhen
JSON.parsethrows aSyntaxError, paste the data in and you can find the wrong comma or quote right away. - Text Diff CheckerPut working code next to broken code, or AI-fixed code next to the original, and see only the lines that changed.
- Quick NotepadWriting down the expected result, the actual result and your hypotheses keeps you from checking the same hypothesis twice and organises the question you'll ask an AI.
- MDN Web Docs — JavaScript error reference
- MDN Web Docs — SyntaxError, ReferenceError, TypeError, RangeError
- MDN Web Docs — Strict mode
- Chrome DevTools documentation — Get started with debugging JavaScript
Reached every goal above? Mark the lesson complete.
Storage is unavailable in this browser, so this lasts only for this page.💻 Coding Basics
- 1What Is a Program? — Breaking Work into Sequence, Choice, and Repetition
- 2Values, Variables, and Types — Putting Name Tags on Values
- 3Conditionals — Taking Different Paths Depending on the Situation
- 4Loops — Doing the Same Thing Many Times, Exactly
- 5Functions — Splitting Work into Small Named Machines
- 6Arrays and Objects — Storing and Handling Data
- 7Strings and Text — Cutting, Finding and Replacing Characters
- 8Debugging and Reading Errors — Turning Red Text into Clues
- 9Simple Automation — Spreadsheet Math and Text Cleanup in Code
- 10Reading and Verifying AI-Written Code — Tests, Security, Licenses, Privacy