While writing JavaScript programs, things won't always go perfectly. A user might enter invalid data, a file might not exist, or an operation might fail for some unexpected reason.
When JavaScript encounters a problem, it can produce an error.
For example:
console.log(username);If username hasn't been defined, JavaScript produces an error such as:
ReferenceError: username is not definedInstead of allowing an error to break the entire flow of our application, JavaScript provides several tools for handling errors gracefully.
What is Error Handling?
Error handling is the process of detecting and managing errors so that a program can respond appropriately instead of failing unexpectedly.
The main tools we'll use are:
trycatchfinallythrow
Common Types of JavaScript Errors
Before handling errors, it's useful to know that JavaScript has different types of built-in errors.
SyntaxError
Occurs when JavaScript code doesn't follow the correct syntax.
if (true {
console.log("Hello");
}The missing ) causes a syntax error.
ReferenceError
Occurs when we try to access a variable that doesn't exist.
console.log(username);TypeError
Occurs when an operation is performed on an inappropriate type of value.
let number = 10;
number.toUpperCase();A number doesn't have a toUpperCase() method, so JavaScript throws a TypeError.
You don't need to memorize every error type right now. The important thing is understanding how to handle errors when they occur.
The try...catch Statement
The most common way to handle runtime errors is try...catch.
Syntax
try {
// Code that might produce an error
} catch (error) {
// Code that handles the error
}For example:
try {
console.log(username);
} catch (error) {
console.log("Something went wrong.");
}Instead of the program immediately stopping at the error, the catch block handles it.
Output:
Something went wrong.The error Object
The catch block receives an error object containing information about what went wrong.
try {
console.log(username);
} catch (error) {
console.log(error);
}You might see:
ReferenceError: username is not definedThe error object also provides useful properties.
error.name
Returns the type of error:
try {
console.log(username);
} catch (error) {
console.log(error.name);
}Output:
ReferenceErrorerror.message
Returns the error message:
try {
console.log(username);
} catch (error) {
console.log(error.message);
}Output:
username is not definedfinally
Sometimes we have code that should run whether an error occurs or not.
That's what finally is for.
try {
console.log("Trying...");
} catch (error) {
console.log("An error occurred.");
} finally {
console.log("Finished.");
}Output:
Trying...
Finished.If an error occurs:
try {
console.log(username);
} catch (error) {
console.log("An error occurred.");
} finally {
console.log("Finished.");
}Output:
An error occurred.
Finished.So:
try → Try the code
catch → Handle an error
finally → Always run this codefinally is often useful for cleanup operations, such as closing a resource or resetting application state.
Throwing Your Own Errors
JavaScript also allows us to create an error ourselves using throw.
For example:
let age = 15;
if (age < 18) {
throw new Error("You must be at least 18 years old.");
}JavaScript will throw an error with our custom message.
We can catch it:
try {
let age = 15;
if (age < 18) {
throw new Error("You must be at least 18 years old.");
}
console.log("Access granted.");
} catch (error) {
console.log(error.message);
}Output:
You must be at least 18 years old.This is useful when we want to say:
"This situation isn't valid, so I'm going to treat it as an error."
throw Can Throw Different Values
Technically, JavaScript allows us to throw almost any value:
throw "Something went wrong";But in modern JavaScript, it's recommended to throw an actual Error object:
throw new Error("Something went wrong");This provides useful information such as the error name, message, and stack trace.
Handling Different Errors
We can inspect the error type inside catch.
try {
JSON.parse("invalid json");
} catch (error) {
if (error instanceof SyntaxError) {
console.log("Invalid JSON format.");
} else {
console.log("Something else went wrong.");
}
}This allows us to respond differently depending on what happened.
Error Handling in Functions
Errors can also be handled inside functions.
function divide(a, b) {
if (b === 0) {
throw new Error("Cannot divide by zero.");
}
return a / b;
}
try {
console.log(divide(10, 0));
} catch (error) {
console.log(error.message);
}Output:
Cannot divide by zero.This pattern is useful because the function detects the invalid situation while the code calling the function decides how to handle it.
Error Handling with User Input
Suppose a user enters an age:
function checkAge(age) {
if (age < 18) {
throw new Error("You must be 18 or older.");
}
return "Access granted.";
}
try {
console.log(checkAge(16));
} catch (error) {
console.log("Error:", error.message);
}Output:
Error: You must be 18 or older.In a real application, we could display this message next to a form field instead of simply printing it to the console.
Error Handling with JSON
A common real-world example is parsing JSON.
Valid JSON:
try {
const data = JSON.parse('{"name":"John"}');
console.log(data.name);
} catch (error) {
console.log("Invalid JSON.");
}Output:
JohnInvalid JSON:
try {
const data = JSON.parse("Hello");
console.log(data);
} catch (error) {
console.log("Invalid JSON.");
}Output:
Invalid JSON.This is a good example of why error handling matters in real applications—data received from outside your program isn't always guaranteed to be valid.
Don't Use try...catch Everywhere
It's important to understand that error handling doesn't mean wrapping your entire program inside try...catch.
For example, this isn't particularly useful:
try {
let x = 10;
let y = 20;
console.log(x + y);
} catch (error) {
console.log("Error");
}There's no operation here that reasonably requires error handling.
Instead, use try...catch when you're dealing with operations that can actually throw errors and where you can meaningfully recover or respond.
Conclusion
Error handling allows JavaScript programs to deal with unexpected situations more safely.
The main tools are:
try → Code that might fail
catch → Handle the error
finally → Code that should always run
throw → Create your own errorA basic example looks like this:
try {
// Risky operation
} catch (error) {
console.log(error.message);
} finally {
// Cleanup
}And when we need to report an invalid situation ourselves:
throw new Error("Something went wrong.");Good error handling doesn't just prevent crashes—it also helps us give users clear and useful feedback when something goes wrong.