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.
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.
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.
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
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.
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:
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.
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.
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.
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:
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.
KES 2,999
Not sure where to begin? This beginner-friendly course covers how computers work, the internet, Git, and your first lines of code — everything you need before picking a stack. 10 modules, 89 lessons.
Start Tech Foundations