Error Handling
try / catch / finally
try {
// code that might throw
const result = JSON.parse("invalid json");
console.log(result);
} catch (error) {
console.error("Error:", error.message);
console.error("Name:", error.name); // "SyntaxError"
console.error("Stack:", error.stack);
} finally {
// ALWAYS runs, even if error or return
console.log("This always runs");
}
Built-in Error Types
// SyntaxError: invalid syntax
JSON.parse("bad json"); // SyntaxError
// ReferenceError: accessing undefined variable
console.log(undeclaredVar); // ReferenceError
// TypeError: wrong type operation
null.toString(); // TypeError
undefined.length; // TypeError
// RangeError: value out of valid range
new Array(-1); // RangeError
(1.234).toFixed(200); // RangeError
// URIError
decodeURIComponent("%"); // URIError
// AggregateError: Promise.any when all reject
Throwing Errors
// Throw any value
throw "Something went wrong";
throw 42;
throw { message: "Custom error" };
// Best practice: throw Error objects
throw new Error("Something went wrong");
throw new TypeError("Expected a string");
throw new RangeError("Value must be between 0 and 100");
Custom Error Classes
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
class NetworkError extends Error {
constructor(message, statusCode) {
super(message);
this.name = "NetworkError";
this.statusCode = statusCode;
}
}
// Using custom errors
try {
const age = -5;
if (age < 0) throw new ValidationError("Age must be positive", "age");
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Validation failed on field: ${error.field}`);
} else if (error instanceof NetworkError) {
console.log(`Network error: ${error.statusCode}`);
} else {
throw error; // re-throw unknown errors!
}
}
Error Handling in Async Code
// With Promises
fetch("/api/data")
.then(res => res.json())
.catch(err => console.error("Fetch error:", err))
.finally(() => setLoading(false));
// With async/await
async function loadData() {
try {
const res = await fetch("/api/data");
if (!res.ok) throw new NetworkError(`HTTP ${res.status}`, res.status);
const data = await res.json();
return data;
} catch (error) {
if (error instanceof NetworkError) {
// handle network errors
} else {
throw error; // re-throw unexpected errors
}
}
}
Global Error Handling
// Browser: unhandled errors
window.addEventListener("error", (event) => {
console.error(event.error);
});
// Browser: unhandled Promise rejections
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled Promise rejection:", event.reason);
event.preventDefault(); // suppress default console error
});
// Node.js
process.on("uncaughtException", (err) => {
console.error("Uncaught:", err);
process.exit(1);
});
process.on("unhandledRejection", (reason, promise) => {
console.error("Unhandled rejection:", reason);
});
MCQ — Error Handling
Q1: What does the finally block do?
A) Runs only if no error occurred B) Runs only if an error occurred C) Always runs, regardless of error or return ✅ D) Runs the error handling code
Answer: C
Q2: Which error type is thrown when calling a method on null?
A) ReferenceError
B) SyntaxError
C) TypeError ✅
D) NullError
Answer: C
Q3: What is best practice when catching errors?
A) Catch all errors with an empty catch block B) Handle specific error types and re-throw unknown errors ✅ C) Log all errors and continue D) Always suppress errors
Answer: B
Q4: How do you create a custom error class?
A) const e = { type: "CustomError", message: "..." }
B) class CustomError extends Error { constructor(...) { super(...); } } ✅
C) function CustomError(msg) { this.message = msg; }
Answer: B
Q5: Which event catches unhandled Promise rejections in the browser?
A) error
B) promiserejection
C) unhandledrejection ✅
D) catch
Answer: C