How to Debug When You Have No Idea What Is Wrong
Start by reading the error message carefully. Most error messages tell you exactly what is wrong and which line of code caused it. If there is no error message, add console.log statements to trace where your code stops behaving as expected. Use browser DevTools to inspect the DOM, check network requests, and view console output. The debugger statement lets you pause execution and step through code line by line. If you are still stuck after 30 minutes, ask for help with the error message and what you have already tried.
Step One: Actually Read the Error Message
This is the most common beginner mistake and it sounds almost insulting to point out. But it is true: most beginners see a red error in the console and immediately panic. They close the console, go back to their code, and start randomly changing things. The error message is not decoration. It is a diagnosis.
Here is a typical JavaScript error:
TypeError: Cannot read properties of undefined (reading 'map')
at UserList (UserList.jsx:12:24)
This tells you three things. The type of error is TypeError, which means you tried to do something with a value that does not support it. The description says you called .map() on something that is undefined. And the location is line 12, column 24 of UserList.jsx. That is your entire investigation. Go to that line, find what you are calling .map() on, and figure out why it is undefined instead of an array.
Not every error message is this clear, but a surprising number of them are. Before you do anything else, read the full message. Google the exact text if you do not understand it. Chances are very high that someone has had the same error and explained it on Stack Overflow.
One more thing: some errors have a "stack trace," which is a list of function calls that led to the error. Read it from top to bottom. The top line is where the error occurred. The lines below show the chain of function calls that got there. This helps you understand not just where the error is, but how your code reached that point.
The Console.log Strategy (It Is Not Cheating)
Some tutorials make console.log sound like a shameful hack that "real developers" do not use. That is nonsense. console.log is the most common debugging tool in the industry. Senior engineers use it daily. The key is using it strategically, not randomly.
The idea is simple: if you do not know where your code breaks, add console.log statements at multiple points to narrow it down.
function processUsers(data) {
console.log('1. data received:', data);
const users = data.results;
console.log('2. users extracted:', users);
const filtered = users.filter(u => u.active);
console.log('3. filtered users:', filtered);
return filtered.map(u => u.name);
}
Run your code and check the console. If you see log 1 but not log 2, the error happens between those two lines. Now you know exactly where to look. If log 1 shows that data is undefined, the problem is not in this function at all. It is wherever this function is being called from.
Label your logs. Never do console.log(data) by itself. When you have five console.log statements, you will not remember which output belongs to which log. Always add a label: console.log('user data from API:', data).
Log the type, not just the value. Sometimes a value looks correct but is the wrong type. console.log(typeof data) reveals whether data is a string, object, undefined, or something else you did not expect.
Clean up when you are done. Remove your debugging console.log statements after you fix the bug. Leaving dozens of log statements in your code makes the console noisy and hard to use next time something breaks.
Browser DevTools: The Dashboard You Are Ignoring
Press F12 (or Cmd+Option+I on Mac) in any browser. That panel that opens is DevTools, and it is one of the most powerful tools you have as a web developer. Most beginners never open it, or only glance at the Console tab. There are several tabs worth knowing.
Console tab. This is where your console.log output appears, and where JavaScript errors show up in red. You can also type JavaScript directly into the console to test things. Want to check if a variable exists? Type its name. Want to test a function? Call it right there.
Elements tab. This shows the live DOM (the HTML structure of your page). You can click on any element to see its CSS styles, computed layout, and event listeners. If something looks wrong visually, click on it in the Elements tab and check the styles panel on the right. You can even edit CSS values live to see what changes would look like before modifying your actual code.
Network tab. This shows every HTTP request your page makes. When your app calls an API and gets no data back, the Network tab shows you the request URL, the response status code (200, 404, 500, etc.), the request headers, and the actual response body. If your API call is failing, this tab tells you exactly why. Check the status code first: 404 means wrong URL, 401 means authentication failed, 500 means the server had an error.
Sources tab. This is where you can set breakpoints (click on a line number to pause execution there) and step through your code. We will cover this more in the debugger section.
You do not need to master every tab right now. Start with Console and Network. Those two alone will solve the majority of bugs you encounter as a beginner. Add Elements when you are debugging CSS issues. Add Sources when you need to step through complex logic.
The Debugger Statement: Pausing Your Code Mid-Flight
console.log shows you values at a specific point. The debugger statement goes further: it pauses your entire program at that line so you can inspect everything.
function calculateTotal(items) {
let total = 0;
for (const item of items) {
debugger; // execution will pause here on each iteration
total += item.price * item.quantity;
}
return total;
}
When your code hits the debugger statement, the browser pauses execution and opens DevTools to the Sources tab. From there you can:
- Hover over variables to see their current values
- Check the Scope panel to see all local and global variables
- Step over (F10) to execute the next line without going into function calls
- Step into (F11) to dive into a function call and see what happens inside
- Resume (F8) to continue execution until the next debugger statement or breakpoint
This is incredibly useful for loops, conditional logic, and any code where the order of operations matters. Instead of adding ten console.log statements to track how a value changes across iterations, one debugger statement lets you watch it change in real time.
You can also set breakpoints directly in the Sources tab by clicking on a line number. This is the same as adding a debugger statement, but without modifying your code. Breakpoints are especially useful when you want to debug code in a library or framework without editing its source files.
Important: remove debugger statements before committing your code. Leaving them in can cause your app to freeze for users who have DevTools closed. Most linting tools (like ESLint) will flag leftover debugger statements as errors.
A Systematic Approach: The Debugging Checklist
When something breaks, resist the urge to start randomly changing code. Follow this order instead.
1. Reproduce the bug. Can you make it happen again? Every time, or only sometimes? What exact steps trigger it? If you cannot reproduce it consistently, you cannot confirm that you have fixed it.
2. Read the error message. Check the browser console. Check your terminal if you have a backend running. Read the full message, including the stack trace.
3. Identify the last change that worked. What did you change right before things broke? If you were adding a feature and things stopped working, the bug is almost certainly in the code you just added. Use git diff to see what changed.
4. Isolate the problem. Comment out sections of code until the error goes away. When commenting out a specific block makes the error disappear, you have found the problem area. Uncomment it and investigate that block specifically.
5. Check your assumptions. Add console.log or use the debugger to verify that variables contain what you think they contain. The most common category of bug is "I assumed this value would be X, but it is actually Y." Logging reveals the mismatch.
6. Search for the error message. Copy the error message (without file paths that are specific to your computer) and paste it into Google. Include the technology name: "React TypeError Cannot read properties of undefined." Almost every common error has been asked about and answered on Stack Overflow.
7. Take a break. This sounds like a joke, but it is real advice. If you have been staring at the same bug for 45 minutes, walk away for ten. Your brain continues processing in the background. Many developers report solving bugs in the shower, on a walk, or the moment they sit back down.
The Bugs That Get Every Beginner
Some bugs are so common among beginners that they deserve their own section. If you are stuck, check these first.
Typos in variable names. JavaScript does not warn you when you create a new variable by misspelling an existing one. userName and username are two different variables. Use your editor's autocomplete to avoid this, and consider using TypeScript, which catches these errors at compile time.
Using = instead of === in comparisons. if (x = 5) assigns 5 to x and always evaluates to true. if (x === 5) checks whether x equals 5. This bug is hard to spot by reading code because the difference is one character.
Forgetting to return in a function. If your function does work but the caller gets undefined, you probably forgot a return statement. Arrow functions with curly braces need an explicit return: (x) => { return x * 2; } or the shorthand (x) => x * 2.
Async/await mistakes. Forgetting to await an async function means you get a Promise object instead of the actual value. If your data shows up as [object Promise] or you see "Promise { <pending> }", add await in front of the function call and make sure the calling function is also marked async.
State updates in React not appearing immediately. React state updates are asynchronous. If you call setCount(count + 1) and then immediately console.log count, you will see the old value. This is not a bug. It is how React works. The new value will be available on the next render.
Off-by-one errors in loops. Arrays are zero-indexed. If your array has 5 items, the last index is 4, not 5. Looping with i <= array.length instead of i < array.length will try to access an element that does not exist.
When to Ask for Help (and How)
There is a balance between struggling productively and wasting time. If you have followed the systematic approach, spent 20 to 30 minutes investigating, and are still stuck, it is time to ask for help. Spending four hours on a bug that someone else can identify in two minutes is not "learning." It is just suffering.
But how you ask matters enormously. "My code does not work, please help" will get ignored. A well-structured question gets answered quickly. Include these things:
- What you are trying to do (one sentence)
- The exact error message (copy-paste, do not screenshot text)
- The relevant code (not your entire file, just the problematic section)
- What you have already tried
- What you expected to happen versus what actually happened
Where to ask. Stack Overflow is good for well-defined technical questions. Discord communities (Reactiflux, The Odin Project, freeCodeCamp) are better for "I am stuck and confused" situations. GitHub Issues are for bugs in open-source projects, not for help with your own code. AI tools like ChatGPT and Claude are excellent for explaining error messages and suggesting fixes, but verify their answers because they sometimes confidently suggest wrong solutions.
If you are in a bootcamp or structured learning program, ask your mentor or cohort first. They have context about your project that strangers on the internet do not. And if you are learning with McTaba Academy, the community and mentor support channels exist specifically for this. Use them.
Key Takeaways
- ✓Read the error message first. It sounds obvious, but most beginners skip the error and start guessing. The message usually tells you the file, the line number, and what went wrong.
- ✓console.log is not a crutch. It is the most widely used debugging tool in professional development. Print values at different points in your code to find where things go wrong.
- ✓Browser DevTools (F12) show you the DOM, network requests, console output, and let you inspect elements. Learning the basics takes an afternoon and saves you hundreds of hours.
- ✓The debugger statement pauses your code mid-execution so you can inspect variables and step through logic line by line. It is more powerful than console.log for complex bugs.
- ✓If you are stuck for more than 30 minutes, ask for help. But include the error message, what you tried, and what you expected to happen.
Frequently Asked Questions
- Is it normal to spend hours on a single bug?
- Yes, especially when you are starting out. Debugging is a skill that improves with practice. What takes you two hours now might take you ten minutes in six months. The key is to use a systematic approach instead of randomly guessing. Over time, you build a mental library of common bugs and their fixes, which speeds up the process dramatically.
- Should I use console.log or the debugger?
- Use both, depending on the situation. console.log is faster for simple checks: "is this value what I think it is?" The debugger is better for complex issues where you need to step through code line by line, especially loops and conditional logic. Most developers use console.log for the majority of debugging and switch to the debugger for trickier problems.
- Can AI tools like ChatGPT help me debug?
- Yes, and they are often faster than searching Stack Overflow. Paste your error message and the relevant code, and AI tools can usually explain the problem and suggest a fix. The caveat: AI tools sometimes suggest solutions that look correct but do not actually work, or that fix the symptom but not the root cause. Always understand why a fix works before applying it. Use AI as a second opinion, not a replacement for understanding.
- How do I debug CSS issues?
- Use the Elements tab in DevTools. Right-click the element that looks wrong and choose "Inspect." The Styles panel on the right shows every CSS rule applied to that element, including which rules are being overridden (shown with a strikethrough). You can toggle rules on and off, change values live, and add new properties to test fixes before changing your actual code.
- What if there is no error message but something still does not work?
- This is the trickiest category of bug. It means your code runs without crashing but produces the wrong result. Start by adding console.log at the input and output of each function involved. Compare the actual values with what you expected. The mismatch will point you to the function where the logic goes wrong. Check your conditionals, your data transformations, and whether you are accidentally mutating data.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon