---
title: Debugging 101: Common JavaScript Errors and How to Fix Them
siteUrl: https://logzly.com/techtrekker
author: techtrekker (Tech Trekker)
date: 2026-06-13T14:57:31.946203
tags: [javascript, debugging, webdev]
url: https://logzly.com/techtrekker/debugging-101-common-javascript-errors-and-how-to-fix-them
---


Ever opened the console and been greeted by a sea of red text that looks like a cryptic poem? If you’ve ever felt that pang of panic when a simple button stops working, you’re not alone. JavaScript is the glue that holds our interactive web experiences together, but it’s also notorious for throwing tantrums that can stall even the most seasoned developers. Today I’m pulling back the curtain on the most frequent JavaScript errors and sharing the exact steps I use to squash them—so you can get back to building cool stuff without the endless “why‑does‑this‑not‑work?” loop.

## The Usual Suspects

### ReferenceError: variable is not defined

**What it means**  
The interpreter tried to read a variable that it has never seen. In plain English: you’re asking for something that doesn’t exist in the current scope.

**Why it happens**  
- A typo in the variable name (`userNmae` instead of `userName`).  
- Forgetting to declare a variable with `let`, `const`, or `var`.  
- Accessing a variable before it’s declared due to hoisting quirks.

**How to fix it**  
1. Open the console and note the line number.  
2. Double‑check the spelling of the identifier.  
3. If the variable should be global, make sure it’s declared at the top level.  
4. If you’re using modules, verify that you’ve exported and imported the symbol correctly.

*Pro tip:* I keep a tiny “watch‑list” of my most common typos in my VS Code settings. When the linter flags an undefined variable, I can instantly see if it’s a simple misspelling.

### TypeError: cannot read property ‘…’ of undefined

**What it means**  
You’re trying to access a property (or call a method) on something that is currently `undefined`.

**Why it happens**  
- The object you expect to exist hasn’t been initialized yet (e.g., an API response that hasn’t arrived).  
- A chain of property accesses where one link is missing (`user.profile.avatar.url`).  
- Misusing `this` inside a callback, causing it to point to the wrong context.

**How to fix it**  
- Guard against `undefined` with optional chaining: `user?.profile?.avatar?.url`.  
- Add a defensive check: `if (user && user.profile) { … }`.  
- When dealing with asynchronous data, make sure you await the promise or handle the callback before touching the object.

*Personal anecdote:* I once spent an hour hunting a `TypeError` that turned out to be a missing `return` statement in a fetch wrapper. Adding the `return` instantly gave me a defined object and saved my sanity.

### SyntaxError: Unexpected token

**What it means**  
The JavaScript parser stumbled over something that doesn’t belong in the grammar—think of it as a typo that breaks the language rules.

**Why it happens**  
- Missing commas, parentheses, or braces (`{ name: "Maya" age: 30 }`).  
- Using a reserved word as an identifier (`class = "hero"`).  
- Copy‑pasting code from a source that introduced invisible characters (yes, those sneaky zero‑width spaces).

**How to fix it**  
- Look at the line number the console points to; the error is often one line before the highlighted spot.  
- Run the snippet through a linter or an online formatter; they’ll highlight the stray token.  
- If you suspect invisible characters, retype the line manually.

*Humor break:* My favorite “unexpected token” is the stray backtick that shows up after I copy a template literal from a Slack message. It’s like the JavaScript equivalent of a rogue sock in the dryer.

### RangeError: Maximum call stack size exceeded

**What it means**  
Your code called a function so many times that the call stack overflowed—essentially, you’ve created an infinite recursion.

**Why it happens**  
- A recursive function missing a base case (`function countDown(n) { return countDown(n-1); }`).  
- Event listeners that trigger each other in a loop.  
- Using `setState` inside a `useEffect` without proper dependency control in React.

**How to fix it**  
- Verify the termination condition of any recursive function.  
- Add a guard clause that stops the recursion after a reasonable depth.  
- In React, ensure your effect’s dependency array is correct, or wrap the state update in a conditional.

*Lesson learned:* The first time I hit this error, I thought my browser had exploded. Turns out a missing `return` in a reducer caused the UI to re‑render forever. A single line saved the day.

## A Debugging Workflow That Actually Works

1. **Read the console, don’t ignore it** – The error message, line number, and stack trace are your first clues.  
2. **Reproduce the bug** – If you can trigger it consistently, you’ll know when you’ve fixed it.  
3. **Isolate the code** – Comment out surrounding logic until the error disappears; then add pieces back one by one.  
4. **Use `console.log` wisely** – Log the values of variables right before the line that throws. Avoid dumping entire objects; focus on the property that’s causing trouble.  
5. **Leverage the debugger** – Chrome’s DevTools let you set breakpoints, step through code, and inspect the call stack. It feels like a detective’s magnifying glass.  
6. **Write a test** – Once you’ve fixed the issue, add a unit test that reproduces the scenario, and commit it using [version control with Git and GitHub](/techtrekker/a-beginners-guide-to-version-control-with-git-and-github). Future you (or a teammate) will thank you when the same bug tries to sneak back in.

## Tools That Make Debugging Less Painful

- **ESLint** – Catches undefined variables and missing semicolons before you even run the code.  
- **Prettier** – Enforces a consistent code style, which reduces the chance of stray commas or mismatched braces.  
- **Source maps** – When you’re working with bundled code (Webpack, Vite), source maps let the console point back to your original files instead of the minified bundle.  
- **Live reload** – Tools like Vite or Next.js refresh the page automatically, so you can see changes instantly without manual refresh.  
- For repetitive linting and formatting, you can automate the process with a small Python utility, similar to the approach in [Automating Daily Tasks with Python](/techtrekker/automating-daily-tasks-with-python-scripts-that-save-you-hours).

## When to Take a Break

Sometimes the console will keep shouting at you, and no amount of `console.log` will make sense of the chaos. In those moments, I step away for a coffee, stare at a plant, or scroll through a gadget review (yes, I’m that person). If you need a quick suggestion, an LLM prompt can surface common fixes—see our guide on [prompt engineering](/techtrekker/understanding-prompt-engineering-tips-to-get-better-results-from-llms). A fresh brain often spots a missing bracket that a tired one glosses over.

## Bottom Line

JavaScript errors are less like random acts of digital vandalism and more like clues left by a mischievous puzzle master. By learning the language of the console, using defensive coding patterns, and keeping a disciplined debugging routine, you’ll turn those red warnings into green checkmarks far more quickly. The next time you see “ReferenceError” or “TypeError,” you’ll know exactly where to look—and you’ll probably have a funny story to tell about the time a stray backtick tried to sabotage your code.