JavaScript Error Handling: try, catch, and finally
Learn JavaScript error handling with try, catch, and finally. This guide covers catching runtime errors, throwing custom errors, handling async errors, and avoiding silent failures.
JavaScript error handling separates code that works in demos from code that works in production. Errors happen — network requests fail, data is missing, functions receive unexpected input. Knowing how to handle them gracefully is essential for any JavaScript developer.
The try/catch Block
Wrap code that might throw an error in try. If an error occurs, execution jumps to catch:
try {
const data = JSON.parse("this is not valid JSON");
} catch (error) {
console.error("Parsing failed:", error.message);
}
Without the try/catch, the invalid JSON parse would crash your script. With it, you handle the error and continue.
The Error Object
The error in catch (error) is an Error object with useful properties:
try {
null.property; // TypeError
} catch (error) {
console.log(error.name); // "TypeError"
console.log(error.message); // "Cannot read properties of null"
console.log(error.stack); // Full stack trace
}
Throwing Custom Errors
You can throw errors intentionally to signal invalid states:
function divide(a, b) {
if (b === 0) {
throw new Error("Division by zero is not allowed");
}
return a / b;
}
try {
const result = divide(10, 0);
} catch (error) {
console.error(error.message);
}
For complex apps, create custom error classes:
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
throw new ValidationError("email", "Invalid email format");
Error Handling with async/await
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error("Failed to fetch user:", error.message);
return null;
}
}
The finally Block
finally runs whether or not an error occurred — perfect for cleanup:
let connection;
try {
connection = await openDatabaseConnection();
await runQuery(connection);
} catch (error) {
console.error(error);
} finally {
if (connection) connection.close(); // Always closes the connection
}
Conclusion
Good JavaScript error handling means your app fails gracefully instead of silently or catastrophically. Use try/catch for anything that can throw, always handle async errors, use finally for cleanup, and throw meaningful errors with clear messages. Your users — and future you — will appreciate it.
Read next: async/await in JavaScript
External resource: MDN — Error Handling Statements
Related Articles
async/await in JavaScript: Making Async Code Readable
Learn how async/await in JavaScript works with clear examples. Understand how it replaces Promise chains, handles errors with try/catch, and makes asynchronous code easier to read.
How to Write Clean Functions in JavaScript
Learn how to write clean JavaScript functions that are easy to read, test, and maintain. This guide covers naming, single responsibility, pure functions, and avoiding common pitfalls.
CSS Flexbox in Plain English: A Beginner's Guide
Learn CSS Flexbox with simple, visual explanations. This guide covers display flex, justify-content, align-items, flex-wrap, and practical layouts every developer needs to know.