Day 18: Errors, try…catch & Debugging
✅ Today you will learn
- Read error messages and stack traces calmly
- Common error types: TypeError, ReferenceError, SyntaxError, RangeError
- try…catch…finally and when (not) to use it
- Throw custom errors and validate early with guard clauses
- Debug with console, breakpoints, watch and the debugger statement
🏢 In the real world
A real support call: “The checkout button does nothing on my phone.” No error is visible to the customer, the developer cannot reproduce it, and orders are lost. Professional developers spend about half their time debugging. The skill is not avoiding all bugs – it is finding them fast and failing gracefully so the customer sees a helpful message instead of a frozen page.
Reading errors
const tests = [
() => undefinedVariable + 1, // ReferenceError
() => null.name, // TypeError
() => (42).toUpperCase(), // TypeError
() => new Array(-1), // RangeError
() => JSON.parse('{bad json}'), // SyntaxError (at runtime, from JSON)
];
for (const t of tests) {
try { t(); } catch (err) { console.log(`${err.name}: ${err.message}`); }
}| Error | Usually means | Typical fix |
|---|---|---|
| ReferenceError: x is not defined | Typo or variable out of scope | Check spelling, declare it, check scope |
| TypeError: Cannot read properties of null/undefined | Element or data missing | Check selector, defer, use ?. and guards |
| TypeError: x is not a function | Wrong name, or the value is not what you think | console.log(typeof x) |
| SyntaxError | Broken code or JSON | Look at the line/column, missing ) } , |
| RangeError | Number out of allowed range / infinite recursion | Check loop and recursion conditions |
| Uncaught (in promise) | A rejected promise with no catch | Add try/catch around await (Day 20) |
The first line is the message, the next line is where it happened (file:line:column). Click it in DevTools to jump to the exact line. Lines below show who called that function.
try…catch…finally
function loadSavedCart(json) {
try {
const cart = JSON.parse(json); // may throw
console.log('Loaded', cart.items.length, 'items');
return cart;
} catch (err) {
console.log('Could not read the saved cart →', err.name);
return { items: [] }; // recover with a safe default
} finally {
console.log('finally: runs either way (hide the loader, close the file…)');
}
}
loadSavedCart('{"items":[{"id":1}]}');
loadSavedCart('{corrupted');Bad use of try…catch
- Wrapping the whole app “just in case”
- catch (e) {} – swallowing errors silently
- Using it instead of checking for null
- Hiding bugs you should fix
Good use ⭐
- Around code that can fail for outside reasons: JSON, storage, network
- Recover with a default or a clear message
- Log enough detail to fix it later
- Re-throw what you cannot handle
Throwing custom errors and guard clauses
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function createOrder({ name, phone, qty }) {
// guard clauses: check bad input first, exit early, keep the happy path flat
if (!name || name.trim().length < 2) throw new ValidationError('name', 'Name is too short');
if (!/^[6-9]\d{9}$/.test(phone)) throw new ValidationError('phone', 'Invalid mobile number');
if (!(qty > 0 && qty <= 50)) throw new ValidationError('qty', 'Quantity must be 0–50 kg');
return { id: 'SS' + 1042, name, phone, qty };
}
for (const input of [{ name: 'Aarti', phone: '9829012345', qty: 2 }, { name: 'Aarti', phone: '12345', qty: 2 }, { name: 'A', phone: '9829012345', qty: 2 }]) {
try {
console.log('✅', createOrder(input).id);
} catch (err) {
if (err instanceof ValidationError) console.log(`⚠️ ${err.field}: ${err.message}`);
else throw err; // unknown problem → do not hide it
}
}console beyond console.log
const order = { id: 1042, items: [{ name: 'Ghewar', qty: 2 }], total: 1300 };
console.log('plain:', order);
console.warn('⚠️ low stock for Ghewar'); // yellow in DevTools
console.error('❌ payment failed for order', order.id);
console.table(order.items);
console.group('Order 1042');
console.log('customer: Aarti');
console.log('total: ₹' + order.total);
console.groupEnd();
console.time('loop');
let s = 0; for (let i = 0; i < 1e6; i++) s += i;
console.timeEnd('loop');
console.assert(order.total > 0, 'total must be positive'); // prints only if false
console.count('render'); console.count('render');Debugging with breakpoints
- 1Reproduce the bug and note the exact steps
- 2DevTools → Sources → open your file (Ctrl+P)
- 3Click a line number to add a breakpoint (or write debugger; in code)
- 4Trigger the action – execution pauses there
- 5Hover variables, use Scope and Watch panels to see real values
- 6Step over (F10), into (F11), out (Shift+F11); resume (F8)
- 7Found it? Fix, then add a test or a guard so it never returns
| Tool | When |
|---|---|
| Conditional breakpoint | Right-click a line → pause only when qty > 50 |
| Event listener breakpoints | Pause on any click or submit without knowing the file |
| DOM breakpoints | Elements → right-click → Break on → subtree modifications |
| Network tab | See requests, status codes and responses (Day 20) |
| Remote debugging | chrome://inspect to debug a real Android phone over USB |
Fail gracefully: global error handling
<button id="ok">Working button</button>
<button id="bad">Buggy button</button>
<div id="toast" role="alert" hidden style="margin-top:10px;padding:10px 14px;border-radius:10px;background:#fee2e2;color:#7f1d1d"></div>
<script>
// Last line of defence: show a friendly message and report the error
window.addEventListener('error', (event) => {
const toast = document.querySelector('#toast');
toast.textContent = 'Sorry, something went wrong. Please try again or call +91 98290 12345.';
toast.hidden = false;
console.error('Reported to developers:', event.message, 'at line', event.lineno);
// in production: send to a logging service (Sentry, your own API) here
});
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise:', event.reason);
});
document.querySelector('#ok').addEventListener('click', () => alert('Order button works ✅'));
document.querySelector('#bad').addEventListener('click', () => {
const cart = null;
return cart.items.length; // 💥 TypeError on purpose
});
</script>🏅 Job skills unlocked today
Practice tasks
🏋️ Practice – do it yourself
Show solution
function safeDivide(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') throw new TypeError('Numbers only');
if (b === 0) throw new RangeError('Cannot divide by zero');
return Math.round(a / b * 100) / 100;
}
for (const [a, b] of [[10, 4], [5, 0], ['5', 1]]) {
try { console.log(`${a} / ${b} =`, safeDivide(a, b)); }
catch (err) { console.log(`${err.name}: ${err.message}`); }
}const total = items.reduce((s, i) => s + i.price * i.qty) gives “[object Object]…”. Explain and fix.Show solution
const items = [{ price: 900, qty: 2 }, { price: 500, qty: 1 }];
// Without a start value, s starts as the FIRST OBJECT, so object + number → string
const wrong = items.reduce((s, i) => s + i.price * i.qty);
const right = items.reduce((s, i) => s + i.price * i.qty, 0);
console.log(wrong);
console.log(right);Quick quiz
🧠 Quick Quiz – test yourself
Interview corner
💼 Interview Corner
How do you debug a bug that only happens in production on mobile?
Collect details (device, browser, steps), check error logging/monitoring for stack traces, reproduce with DevTools device mode and remote debugging (chrome://inspect), check network failures and feature support, add logging around the suspicious code, then fix and add a regression test or guard.
When should you use try…catch?
Around operations that can fail for reasons outside your control – parsing, storage, network, third-party code – where you can recover or show a useful message. Not as a substitute for validation or to silence programming errors.
Summary
- Read the message and the first stack line; learn the 5 common error types.
- try…catch…finally around outside failures; recover or re-throw.
- Custom errors + guard clauses make problems obvious.
- console methods, breakpoints and global handlers find and contain bugs.
Day 19: asynchronous JavaScript – the event loop, timers, callbacks and promises.
