← thecodex.expert · The Codex Family of Knowledge
The Codex / JavaScript / Debugging JavaScript

Debugging JavaScript

Reading error messages, using browser DevTools, breakpoints, console methods, and systematic debugging techniques.

What it is, in plain English: Debugging is the process of finding and fixing errors in code. JavaScript gives you two main environments to debug in: the browser DevTools (Sources tab, Console, Network, Performance) and the Node.js debugger (via --inspect or VS Code). The most important skill is reading the error message and stack trace correctly — they tell you exactly where the problem is.
Where this bites you

console.log("user: " + user) looks like it should print the user, but + converts the object to a string before console.log ever sees it. Plain objects become the useless [object Object], and arrays lose their brackets, so ["pen", "book"] prints as pen,book and you can't tell one item with a comma from two items. The log you added to find a bug hides the very thing you wanted to see.

const user = { name: "Asha", cart: ["pen", "book"] };

console.log("user: " + user);               // + turns the object into a string first
console.log("cart: " + user.cart);
// user: [object Object]
// cart: pen,book

Reading errors and using the console

Step 1: Read the error message

// Every JavaScript error tells you three things:
// 1. The ERROR TYPE
// 2. The MESSAGE (what went wrong)
// 3. The STACK TRACE (where in your code it happened)

// Example error:
// TypeError: Cannot read properties of undefined (reading 'name')
//   at getUsername (app.js:15:22)
//   at handleLogin (app.js:8:18)
//   at HTMLButtonElement.onclick (index.html:23)

// Reading it:
// TypeError     — type of error (wrong type being used)
// "reading 'name'" — you tried to access .name on something undefined
// app.js:15:22  — line 15, column 22 of app.js ← GO HERE FIRST
// The rest shows what called what (call stack, bottom-to-top = oldest to newest call)

Common errors and what they mean

// TypeError — wrong type
// "Cannot read properties of null (reading 'X')" → something is null
// "X is not a function" → you're calling something that isn't a function
// "Cannot set properties of undefined" → parent object doesn't exist

// ReferenceError — variable doesn't exist
// "X is not defined" → the variable was never declared, or you misspelled it
// (using a let/const before its line gives "Cannot access 'X' before initialization" instead)

// SyntaxError — invalid code
// "Unexpected token" → missing bracket, comma, or typo in the code itself

// RangeError — value out of valid range
// "Maximum call stack size exceeded" → infinite recursion!

// Solving them:
const user = null;
// user.name  → TypeError: Cannot read properties of null
const safeName = user?.name ?? "Anonymous";  // fix: use optional chaining

Pass values to console.log as separate arguments, with a comma rather than +, as the suspectFunction example in the Intermediate tab does. The console then shows the real object, which you can expand in DevTools. When you do need a single string (for a log file, say), serialise it deliberately:

const user = { name: "Asha", cart: ["pen", "book"] };

console.log("user:", user);                 // a comma passes the object itself
console.log("cart:", user.cart);
console.log(`user: ${JSON.stringify(user)}`);   // or serialise it on purpose
// user: { name: 'Asha', cart: [ 'pen', 'book' ] }
// cart: [ 'pen', 'book' ]
// user: {"name":"Asha","cart":["pen","book"]}

console methods beyond console.log

// Different severity levels (show differently in DevTools):
console.log("info message");
console.warn("warning — check this");   // yellow in DevTools
console.error("error — something wrong"); // red, includes stack trace

// console.table — perfect for arrays of objects:
console.table([
  { name: "Alice", score: 95 },
  { name: "Bob",   score: 87 },
]);

// console.group — organise related logs:
console.group("Checkout process");
  console.log("Cart validated");
  console.log("Payment processed");
  console.log("Email sent");
console.groupEnd();

// console.time — measure how long something takes:
console.time("my operation");
// ... code ...
console.timeEnd("my operation");  // "my operation: 12.3ms"

Using browser DevTools (the most powerful tool)

// Open DevTools: F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)

// Console tab:
//   - See all errors (red), warnings (yellow), logs
//   - Type JS directly — access your page's variables and functions
//   - Click the filename in errors to jump to the code

// Sources tab — the debugger:
//   - Find your JS file, click a line number to add a BREAKPOINT
//   - Reload the page — execution stops at your breakpoint
//   - Inspect all variable values at that moment
//   - Step through code line by line with F10 (step over) or F11 (step into)

// Network tab:
//   - See all HTTP requests your page makes
//   - Check status codes, request/response bodies
//   - Perfect for debugging fetch() calls

// The 'debugger' statement — set a breakpoint from code:
function processOrder(order) {
  debugger;  // DevTools will pause here (only when DevTools is open)
  return order.items.reduce((sum, item) => sum + item.price, 0);
}
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.