Skip to main content

Error Handling

try / catch / finally

try {
const data = JSON.parse("invalid json");
} catch (error) {
console.error(error.message); // "Unexpected token i in JSON..."
console.error(error.name); // "SyntaxError"
console.error(error.stack); // full stack trace
} finally {
console.log("always runs"); // cleanup code
}

Error Types

Error TypeWhen
SyntaxErrorInvalid syntax
ReferenceErrorVariable not found
TypeErrorWrong type operation
RangeErrorValue out of range
URIErrorBad URI functions
EvalErrorError in eval()

Throwing Errors

function divide(a, b) {
if (b === 0) throw new Error("Cannot divide by zero");
return a / b;
}

// You can throw anything
throw "error string";
throw 404;
throw { message: "not found", code: 404 };
throw new TypeError("Expected a number");

Custom Errors

class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}

try {
throw new ValidationError("email", "Invalid email format");
} catch (error) {
if (error instanceof ValidationError) {
console.log(`${error.field}: ${error.message}`);
}
}

Async Error Handling

// Promise
fetch("/api")
.then((res) => res.json())
.catch((err) => console.error(err));

// Async/Await
async function getData() {
try {
const res = await fetch("/api");
return await res.json();
} catch (err) {
console.error("Request failed:", err);
}
}

// Global handlers
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled promise rejection:", event.reason);
});

Key Takeaways

  • Always wrap risky code in try/catch.
  • Create custom error classes for domain-specific errors.
  • Use finally for cleanup that must always run.
  • Handle async errors with .catch() or try/catch in async functions.