The difference between struggling coders and professionals isn't writing bug-free code-it's efficiently diagnosing and fixing problems. Amateur approach: Random code changes, refresh 50 times, give up. Professional approach: Systematic DevTools inspection, strategic logging, AI-assisted debugging. This lesson teaches production-ready workflows to hunt down bugs confidently.
Opening DevTools: F12 (Windows/Linux) or Cmd+Option+I (Mac) or right-click -> "Inspect Element"
Four Essential Tabs:
View errors with stack traces:
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
at checkAnswer (game.js:45)
Reading errors: Error type -> Problem description -> File location (click to jump!) -> Call stack
Test JavaScript live:
// Console playground - no file editing needed
testWord.toLowerCase() // "apple"
gameState // {score: 10, currentWord: "bee"}
typeof currentWord // "undefined" ← Bug revealed!
Error types: Red (blocking errors - fix first) -> Yellow (warnings) -> Blue (info)
Access: Click pointer icon (top-left DevTools) -> hover -> click element OR right-click -> "Inspect Element"
Live editing: Modify HTML/CSS instantly (not saved to files - perfect for testing)
Common fixes:
display: none or visibility: hiddenAccess: DevTools -> Network tab -> Refresh page to record requests
Debug API issues:
API wrong data → Check: Request URL params, Response preview, Status (200 vs error)
CORS error → Status: (failed), Solution: Add server headers or use CORS proxy
Image won't load → Status: 404 (path), 403 (permissions), 200 (CSS hiding)
Slow performance → Time column >1s → Optimize: pagination, caching, lazy loading
💡 Tip: Right-click request -> "Copy as fetch" -> Paste in Console or send to AI
Access: Application/Storage tab -> Local Storage -> Your domain -> View/edit keys (double-click to edit)
Common issue - Data doesn't persist:
// ❌ Wrong: sessionStorage clears on close
sessionStorage.setItem('gameState', data);
// ❌ Wrong: Missing setItem call
gameState.level = 5;
// ✅ Correct
localStorage.setItem('gameState', JSON.stringify(gameState));
Test edge cases: Manually edit localStorage with corrupted data ({"level":"invalid"}), max values, empty arrays
💡 Tip: Wrap
JSON.parse()in try-catch to handle corrupted data
| Action | Windows/Linux | Mac |
|---|---|---|
| Open DevTools | F12 or Ctrl+Shift+I |
Cmd+Option+I |
| Inspect Element | Ctrl+Shift+C |
Cmd+Shift+C |
| Hard refresh (clear cache) | Ctrl+Shift+R |
Cmd+Shift+R |
Golden rule: Don't know a variable's value? Log it!
| Method | Use Case | Visual |
|---|---|---|
console.log('Label:', value) |
General debugging | Default |
console.error('ERROR:', value) |
Critical problems | Red |
console.warn('WARNING:', value) |
Warnings | Yellow |
console.table(array) |
Arrays/objects | Table |
Strategic checkpoints - Log at critical execution points:
function checkAnswer(userInput) {
console.log('=== checkAnswer() ===');
console.log('Input:', userInput, 'Expected:', currentWord);
if (!currentWord) {
console.error('currentWord undefined!');
return false;
}
const isCorrect = userInput.toLowerCase() === currentWord.toLowerCase();
console.log('Is correct?', isCorrect);
return isCorrect;
}
Object logging:
// ❌ Bad: 'State: ' + gameState → [Object object]
// ✅ Good: console.log('State:', gameState) → Expandable object
// ✅ JSON: JSON.stringify(gameState, null, 2) → Formatted
Production cleanup: Comment out or use conditional if (DEBUG) wrapper. Keep console.error() for user-reported bugs.
AI excels at: Error interpretation, syntax fixes, explaining failures, alternative approaches
AI struggles with: Custom business logic bugs, intermittent bugs, performance issues without context
Rule of thumb: Error message? -> AI immediately. Behavioral bug? -> Manual debug first, then AI
Step One: Copy full error with stack trace (not just error type - include file locations and call chain)
Step 2: Provide context
❌ Bad: "I got TypeError: Cannot read property"
✅ Good:
Building Spelling Bee game. Error on Submit button click:
TypeError: Cannot read property 'toLowerCase' of undefined at checkAnswer (game.js:45)
Code:
function checkAnswer(userInput) {
if (userInput.toLowerCase() === currentWord.toLowerCase()) return true;
return false;
}
Expected: currentWord set by displayNewWord()
Actual: currentWord is undefined
Step 3: Test AI suggestion -> Apply fix -> Test -> Understand why it works
Step 4: Iterate -> Report results -> Get refined fix -> Repeat until resolved
AI pattern recognition:
Error debugging:
Working on [project]. Error when [action]:
[Full error + stack trace]
Code: [Paste function]
Expected: [What should happen]
Actual: [What's happening]
Behavioral bugs:
Building [feature] in [project].
Expected: [Correct behavior]
Actual: [Wrong behavior]
Code: [Paste functions]
Tried: [Attempted fixes]
💡 Token Management: See Concept 15: AI Collaboration at Scale for strategies on minimizing context and optimizing debugging costs
Using debugger statement:
// File: game.js
function startLevel(level) {
debugger; // ← Pauses execution, opens DevTools
loadLevelData(level);
}
// File: levelLoader.js
function loadLevelData(level) {
debugger; // ← Another pause point
const data = fetchLevelData(level);
}
Navigation: F10 (step over) | F11 (step into) | F8 (continue)
Use when: console.log() insufficient - need exact state at specific moment
Strategy: Add labeled console checkpoints to identify file boundaries
// File: gameController.js
export function updateScore(points) {
console.log('[gameController] updateScore:', points);
const newScore = calculateScore(points);
console.log('[gameController] Calculated:', newScore);
saveScore(newScore);
}
// File: storage.js
export function saveScore(score) {
console.log('[storage] saveScore:', score);
localStorage.setItem('score', score);
}
If [storage] logs missing -> bug is in file connection (import/export)
Common import/export bugs:
// ❌ Named export, default import
export function calc() {}
import calc from './utils.js'; // WRONG
// ✅ Fix
import { calc } from './utils.js';
// ❌ Circular dependencies - move shared state to separate file
Strategic breakpoint placement:
Debug flow: Trigger bug -> Pause at breakpoint 1 -> Inspect data -> F8 continue -> Find where data corrupts
☐ 1. REPRODUCE: Document exact steps, test browsers, note patterns
☐ 2. DEVTOOLS: Console errors? Network API calls? Application state?
☐ 3. ISOLATE FILE: Console checkpoints → Identify file/function
☐ 4. NARROW LINE: Debugger/logs → Pinpoint exact line
☐ 5. HYPOTHESIS: "Bug caused by X because..." → Test fix
☐ 6. USE AI: Send 1-2 files max | Haiku (simple) vs Sonnet (complex) | Include: error + expected + actual
☐ 7. VERIFY: Test reproduction steps + edge cases + remove logs
Example: Chatbot stops after 5 messages
✓ Reproduce: Always 5 messages
✓ DevTools: Console TypeError, Network 429 (rate limit)
✓ Isolate: chat.js sendMessage()
✓ Narrow: Crashes at data.response (no error handling)
✓ Hypothesis: Rate limit hit, missing try-catch
✓ AI (Haiku): "Add 429 error handling" → $0.0005
✓ Verify: Fixed! 10min total (5min manual + 5min AI)
Step One: Reproduce Consistently
Document: Trigger action, frequency (always/random), browser, conditions
Step 2: Isolate Problem
Console checkpoints reveal missing logs:
function submitAnswer() {
console.log('1. Called');
const userInput = document.getElementById('answer').value;
console.log('2. Input:', userInput);
const isCorrect = checkAnswer(userInput);
console.log('3. Correct?', isCorrect);
if (isCorrect) {
console.log('4. Updating...');
updateScore(10);
console.log('5. Updated'); // ← Missing? Bug in updateScore()
}
}
Step 3: Hypothesis -> Test -> Repeat
// Hypothesis: gameState.score undefined
console.log(gameState); // {difficulty: 'easy'} ← Missing score!
// Fix: Initialize
gameState = { difficulty: 'easy', score: 0, streak: 0 };
// Test: Refresh → Submit → Console: "New score: 10" ✓
Step 4: Verify Fix
Test: Original steps, edge cases (negative score, max values), no new bugs, add comments
Error message? → YES → AI immediately → Test fix → Works? Done | Fails? Report back
↓
NO (behavioral bug) → Manual debug 20min → Stuck? → AI with isolated code
Score doesn't persist: Add localStorage.setItem('gameState', JSON.stringify(gameState))
Wrong word displays: Filter out used words before random selection
Hints don't work: Check button ID exists, verify event listener attached, log currentWord
Game freezes: Log available vs used words count to detect infinite loops
DevTools Mastery:
F12 (open), Ctrl/Cmd+Shift+R (hard refresh)Strategic Logging:
AI Debugging:
Systematic Process:
Production Checklist: Reproduce -> DevTools -> Isolate -> Narrow -> Hypothesize -> AI -> Verify
💡 Remember: Bugs are learning opportunities. Professional debugging = efficiency + cost management.
Professional Mindset:
Workflow: Error -> Console -> AI (if unclear) -> Isolate -> Hypothesis -> Test -> Verify -> Remove logs
Cost Hierarchy:
Free: console.log, DevTools
$0.0005: Haiku (syntax)
$0.02: Sonnet (complex)
$0.30+: Entire codebase (avoid!)
Practice debugging workflow:
F12)Every bug strengthens your debugging mastery!