Here is the complete list of JavaScript Error Handling methods categorized by their primary functions.
What is Error Handling?
Error handling is the process of anticipating, detecting, and managing errors that occur during program execution. Without proper error handling, unexpected errors can crash your application. JavaScript provides the try...catch...finally statement to handle errors gracefully.
| Feature | Purpose |
|---|---|
try | Wraps code that might throw an error |
catch | Handles the error if one is thrown |
finally | Runs cleanup code regardless of error |
throw | Manually throws an error |
| Custom Errors | Create domain-specific error classes |
| Global handlers | Catch unhandled errors application-wide |
Proper error handling makes your applications robust, maintainable, and user-friendly. Always anticipate potential errors and handle them gracefully!
The try...catch Block
The try...catch statement allows you to test code for errors and handle them without stopping execution.
Basic Syntax:
try {
// Code that might throw an error
} catch (error) {
// Code to handle the error
}
Simple Example:
try {
const result = 10 / 2;
console.log(result); // 5
} catch (error) {
console.log("An error occurred:", error.message);
}
Example with an Error:
try {
const obj = null;
console.log(obj.name); // TypeError: Cannot read property 'name' of null
} catch (error) {
console.log("Caught error:", error.message); // "Cannot read property 'name' of null"
}
Error Object Properties
When an error is caught, the error object contains useful information:
name- The type of error (e.g.,TypeError,ReferenceError,SyntaxError)message- A description of the errorstack- The stack trace showing where the error occurred
Example:
try {
throw new Error("Something went wrong!");
} catch (error) {
console.log("Name:", error.name); // "Error"
console.log("Message:", error.message); // "Something went wrong!"
console.log("Stack:", error.stack); // Full stack trace
}
Built-in Error Types
JavaScript has several built-in error types:
ReferenceError
Thrown when referencing an undefined variable.
try {
console.log(undefinedVariable);
} catch (error) {
console.log(error.name); // "ReferenceError"
}
TypeError
Thrown when performing an invalid operation on a value.
try {
const str = "hello";
str.forEach(char => console.log(char)); // strings don't have forEach
} catch (error) {
console.log(error.name); // "TypeError"
}
SyntaxError
Thrown when invalid code syntax is encountered (usually caught during parsing).
// This would be caught by the parser, not try-catch
// const x = {invalid syntax here};
RangeError
Thrown when a numeric value is out of range.
try {
const arr = new Array(-1); // Invalid array length
} catch (error) {
console.log(error.name); // "RangeError"
}
SyntaxError (eval)
When using eval() with invalid code:
try {
eval("const x = {invalid}");
} catch (error) {
console.log(error.name); // "SyntaxError"
}
The finally Block
The finally block executes regardless of whether an error occurred. Use it for cleanup operations like closing files, releasing resources, or logging.
Syntax:
try {
// Code that might throw an error
} catch (error) {
// Handle the error
} finally {
// Code that always runs
}
Example:
let file = null;
try {
file = openFile("data.txt");
console.log("File opened successfully");
throw new Error("Processing failed");
} catch (error) {
console.log("Error:", error.message);
} finally {
if (file) {
closeFile(file);
console.log("File closed");
}
}
// Output:
// Error: Processing failed
// File closed
Throwing Custom Errors
You can throw your own errors using the throw statement.
Basic Example:
function validateAge(age) {
if (age < 0 || age > 150) {
throw new Error("Invalid age");
}
return "Age is valid";
}
try {
console.log(validateAge(-5));
} catch (error) {
console.log("Validation error:", error.message); // "Validation error: Invalid age"
}
Throwing with Specific Error Types:
function validateEmail(email) {
if (!email.includes("@")) {
throw new TypeError("Email must contain @");
}
return "Email is valid";
}
try {
validateEmail("invalidemail.com");
} catch (error) {
if (error instanceof TypeError) {
console.log("Type error:", error.message);
}
}
Creating Custom Error Classes
Create custom error classes for domain-specific errors.
Example:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
class NotFoundError extends Error {
constructor(resource) {
super(`${resource} not found`);
this.name = "NotFoundError";
}
}
try {
throw new ValidationError("Invalid input provided");
} catch (error) {
console.log(error.name); // "ValidationError"
console.log(error.message); // "Invalid input provided"
}
try {
throw new NotFoundError("User");
} catch (error) {
console.log(error.name); // "NotFoundError"
console.log(error.message); // "User not found"
}
Nested try...catch Blocks
You can nest try...catch blocks to handle different error scenarios.
Example:
try {
try {
throw new Error("Inner error");
} catch (innerError) {
console.log("Inner catch:", innerError.message);
throw new Error("Re-thrown error");
}
} catch (outerError) {
console.log("Outer catch:", outerError.message);
}
// Output:
// Inner catch: Inner error
// Outer catch: Re-thrown error
Error Handling in Promises
When working with promises, use .catch() or try...catch with async/await.
Using .catch():
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
console.log("Fetch error:", error.message);
});
Using async/await with try...catch:
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.log("Error fetching data:", error.message);
}
}
fetchData();
Error Handling with Async/Await
Example – Multiple async operations:
async function loadUserData() {
try {
const userResponse = await fetch("/api/user");
const user = await userResponse.json();
const postsResponse = await fetch(`/api/posts/${user.id}`);
const posts = await postsResponse.json();
console.log("User:", user);
console.log("Posts:", posts);
} catch (error) {
console.log("Error loading data:", error.message);
} finally {
console.log("Data loading complete");
}
}
loadUserData();
Global Error Handler
Catch unhandled errors globally using window.onerror or window.onunhandledrejection.
For synchronous errors:
window.onerror = function(message, source, lineno, colno, error) {
console.log("Global error caught:", message);
console.log("Source:", source);
console.log("Line:", lineno);
return true; // Prevents default error handling
};
For unhandled promise rejections:
window.onunhandledrejection = function(event) {
console.log("Unhandled promise rejection:", event.reason);
};
Practical Examples
Form Validation Error Handling
function validateForm(formData) {
try {
if (!formData.name || formData.name.trim() === "") {
throw new Error("Name is required");
}
if (!formData.email || !formData.email.includes("@")) {
throw new Error("Valid email is required");
}
if (!formData.password || formData.password.length < 8) {
throw new Error("Password must be at least 8 characters");
}
return { success: true, data: formData };
} catch (error) {
return { success: false, error: error.message };
}
}
const result = validateForm({ name: "John", email: "john@example.com", password: "short" });
console.log(result);
// { success: false, error: "Password must be at least 8 characters" }
API Call with Retry Logic
async function fetchWithRetry(url, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Failed after ${maxRetries} attempts`);
}
await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); // Exponential backoff
}
}
}
fetchWithRetry("https://api.example.com/data")
.then(data => console.log("Success:", data))
.catch(error => console.log("Final error:", error.message));
JSON Parsing with Error Handling
function safeJSONParse(jsonString, fallback = null) {
try {
return JSON.parse(jsonString);
} catch (error) {
console.log("JSON parse error:", error.message);
return fallback;
}
}
const data1 = safeJSONParse('{"name":"John"}');
console.log(data1); // { name: "John" }
const data2 = safeJSONParse('invalid json', {});
console.log(data2); // {}
Best Practices
Be specific: Catch specific errors rather than all errors indiscriminately.
Use finally for cleanup: Always use
finallyfor resource cleanup (closing files, connections).Log errors properly: Log errors with context for debugging (include timestamps, user info, etc.).
Re-throw when appropriate: Don't silently swallow errors; re-throw or handle them meaningfully.
Provide user feedback: Show user-friendly error messages, not technical jargon.
Validate input: Prevent errors by validating input early.
Use custom error classes: Create specific error types for different scenarios.
Test error paths: Write tests for error handling code.
Use async/await with try...catch: It's more readable than promise chains.
Implement global error handlers: Catch unhandled errors at the application level.