Error Handling & Debugging
try / catch / finally
try {
const data = JSON.parse(rawInput); // throws on invalid JSON
process(data);
} catch (error) {
console.error("Invalid input:", error.message);
} finally {
hideSpinner(); // always runs
}Throw Error objects (never bare strings — they lose the stack trace):
function setPrice(amount) {
if (amount < 0) {
throw new Error(`price cannot be negative, got ${amount}`);
}
}Custom Error Classes
class ApiError extends Error {
constructor(status, message) {
super(message);
this.name = "ApiError";
this.status = status;
}
}
try {
await api("/courses");
} catch (err) {
if (err instanceof ApiError && err.status === 401) {
redirectToLogin();
} else {
throw err; // don't swallow what you can't handle
}
}Async Errors
With await, rejected Promises become throwable — regular try/catch works. Without it, you need .catch():
// fire-and-forget still needs a handler
saveDraft().catch(err => console.error("autosave failed", err));Global last-resort traps (for logging services like Sentry):
window.addEventListener("error", e => report(e.error));
window.addEventListener("unhandledrejection", e => report(e.reason));Debugging Beyond console.log
Breakpoints beat print statements. In DevTools → Sources, click a line number, reload, and execution pauses there: inspect every variable, hover over expressions, step line by line (F10 step over, F11 step into, F8 resume). Or drop a breakpoint from code:
function calculateTotal(cart) {
debugger; // pauses here when DevTools is open
...
}Console power-ups:
console.table(users); // arrays of objects as a table
console.group("checkout"); ... console.groupEnd();
console.time("render"); ... console.timeEnd("render"); // quick timing
console.trace(); // who called me?Reading a Stack Trace
TypeError: Cannot read properties of undefined (reading 'name')
at renderCard (app.js:42:18)
at app.js:51:9Top line: what happened and where. undefined (reading 'name') means you did something.name where something was undefined — work backwards from line 42 to find which variable, and why it was undefined. The Network tab (failed requests) and the “Pause on exceptions” button cover most of the rest of real-world debugging.