Error Handling in JavaScript
Try, Catch and Finally

What are Errors in JavaScript?
Errors in JavaScript are issues that occur during the execution of your code. These are typically categorized as:
Syntax Errors – Mistakes in code structure (caught before execution)
Runtime Errors – Occur while the program is running
Logical Errors – Code runs, but produces incorrect results
Example of a Runtime Error
let user = null;
console.log(user.name); // ❌ TypeError: Cannot read properties of null
This error occurs because you're trying to access a property (name) of a null value.
Error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions. See below for standard built-in error types.
Using try...catch Blocks
To prevent your application from crashing due to runtime errors, JavaScript provides the try...catch mechanism. The try...catch construct has two main blocks: try, and then catch:
Basic Syntax:
try {
// Code that might throw an error
} catch (error) {
// Code to handle the error
}
Example:
try {
let data = JSON.parse('invalid json');
} catch (error) {
console.log('Something went wrong:', error.message);
}
Instead of breaking the app, the error is caught and handled gracefully.
It works like this:
First, the code in
try {...}is executed.If there were no errors, then
catch (err)is ignored: the execution reaches the end oftryand goes on, skippingcatch.If an error occurs, then the
tryexecution is stopped, and control flows to the beginning ofcatch (err). Theerrvariable (we can use any name for it) will contain an error object with details about what happened.
The finally Block
The finally block runs regardless of whether an error occurred or not. It's useful for cleanup tasks like closing resources or stopping loaders.
Syntax
try {
// risky code
} catch (error) {
// handle error
} finally {
// always runs
}
Example
try {
console.log('Trying...');
} catch (error) {
console.log('Error occurred');
} finally {
console.log('Cleanup done');
}
Throwing Custom Errors
You can manually throw errors using the throw keyword. This is useful when you want to enforce certain conditions in your code.
Example
function withdraw(amount) {
if (amount <= 0) {
throw new Error("Amount must be greater than zero");
}
console.log("Withdrawal successful");
}
try {
withdraw(-100);
} catch (error) {
console.log(error.message);
}
You can also throw custom error types:
class CustomError extends Error {
constructor(foo = "bar", ...params) {
// Pass remaining arguments (including vendor specific ones) to parent constructor
super(...params);
// Maintains proper stack trace for where our error was thrown (non-standard)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
this.name = "CustomError";
// Custom debugging information
this.foo = foo;
this.date = new Date();
}
}
try {
throw new CustomError("baz", "bazMessage");
} catch (e) {
console.error(e.name); // CustomError
console.error(e.foo); // baz
console.error(e.message); // bazMessage
console.error(e.stack); // stack trace
}
Why Error Handling Matters?
Prevents Application Crashes: Without proper handling, a single error can break your entire app.
Improves User Experience: Instead of showing raw error messages, you can display user-friendly feedback.
Helps in Debugging: Error handling allows you to log useful information, making bugs easier to trace and fix.
Enables Graceful Failure: Your app can continue functioning even when something goes wrong.
Graceful Failure Explained
Graceful failure means your application doesn't completely stop when an error occurs—it adapts.
Example
try {
let result = riskyFunction();
display(result);
} catch (error) {
display("Something went wrong. Please try again.");
}
Instead of crashing, the app shows a fallback message.
Debugging Benefits
Error handling helps you:
Capture stack traces
Log meaningful error messages
Track down bugs faster
Integrate with monitoring tools (like Sentry)
Conclusion
Use
try...catchto handle runtime errors safelyUse
finallyfor cleanup tasksThrow custom errors for better control and clarity
Always aim for graceful failure instead of crashes
Good error handling = better user experience + easier debugging





