Chapter 13 of 14
Errors in JavaScript are objects that describe what went wrong. Handling them gracefully — rather than letting them crash your application — is what separates working software from fragile demos.
// try — code that might throw an error
// catch — runs if an error occurs in try
// finally — always runs, regardless of success or failure
try {
const data = JSON.parse(invalidJson); // throws SyntaxError
processData(data);
} catch (error) {
console.error("Parsing failed:", error.message);
// error.name — "SyntaxError"
// error.message — "Unexpected token i in JSON..."
// error.stack — full stack trace
} finally {
console.log("Always runs — cleanup here");
}// With async/await — wrap in try/catch
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`User ${id} not found (status ${response.status})`);
}
return await response.json();
} catch (error) {
if (error.name === "TypeError") {
console.error("Network error — are you offline?", error);
} else {
console.error("Fetch error:", error.message);
}
return null; // return a safe fallback
}
}// Create custom error classes for meaningful error handling
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
function validateEmail(email) {
if (!email.includes("@")) {
throw new ValidationError("email", "Email must contain @");
}
}
try {
validateEmail("not-an-email");
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Field "${error.field}" invalid: ${error.message}`);
}
}WARNING
Don't silently swallow errors. A common beginner mistake is catching errors and doing nothing: catch (err) {}. This hides bugs that are now impossible to debug. At minimum, console.error(err). In production, log errors to a monitoring service.