JavaScript error handling is the process of detecting, managing, and responding to errors that occur while a program runs. It helps developers prevent unexpected failures, display useful error messages, and build more reliable applications.
Errors can occur for several reasons, such as writing invalid syntax, accessing an undefined property, or performing an operation with incorrect data.
JavaScript provides several tools for handling errors, including try, catch, finally, and throw. Understanding these tools helps you identify problems and handle them without unnecessarily interrupting the entire application.
In this tutorial, you will learn about JavaScript errors, syntax errors, runtime errors, logical errors, and how to handle exceptions using practical examples.
What Is Error Handling in JavaScript?
Error handling is the process of identifying errors and deciding what a program should do when they occur.
For example, consider a program that divides two numbers.
const result = 10 / 0;
console.log(result);
Output:
Infinity
JavaScript does not throw an error when a number is divided by zero. Instead, it produces Infinity. This result may not be what your application expects, so you may need to validate the input.
Here is an example with error handling:
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
The function throws an error when the divisor is zero. The catch block handles the error and displays its message instead of allowing the exception to go unhandled.
Types of Errors in JavaScript
JavaScript errors can be grouped into several categories. Understanding the type of error helps you find and fix the underlying problem.
The main categories are:
- Syntax errors
- Runtime errors
- Logical errors
JavaScript also provides built-in error types, such as TypeError, ReferenceError, and RangeError.
Syntax Errors in JavaScript
A syntax error occurs when JavaScript code violates the language’s grammar rules.
The engine cannot correctly parse the invalid code, so that script or module cannot execute as intended.
Example of a Syntax Error
if (10 > 5 {
console.log("Ten is greater");
}
The opening parenthesis in the if condition is not properly closed before the opening brace.
A corrected version is:
if (10 > 5) {
console.log("Ten is greater");
}
Output:
Ten is greater
Common Causes of Syntax Errors
Syntax errors commonly occur because of:
- Missing closing parentheses or braces.
- Missing quotation marks in strings.
- Incorrectly written keywords.
- Invalid expressions.
- Incorrect punctuation or operators.
For example:
const name = "Karim;
This code contains an unterminated string because the closing quotation mark is missing.
Correct version:
const name = "Karim";
console.log(name);
Output:
Karim
Important: A syntax error in a script prevents that script from executing normally. Wrapping the invalid source text in an ordinary try...catch block does not make the surrounding script’s syntax error catchable at runtime.
Runtime Errors in JavaScript
A runtime error occurs while a program is executing. The code may be syntactically valid, but an operation fails during execution.
Runtime errors often produce exceptions that can be handled with try...catch.
Example of a Runtime Error
const user = null;
console.log(user.name);
This code throws a TypeError because JavaScript cannot read the name property of null.
A safer version is:
const user = null;
try {
console.log(user.name);
} catch (error) {
console.log("Something went wrong:", error.message);
}
Output:
Something went wrong: Cannot read properties of null (reading 'name')
The exact error message may vary between JavaScript engines.
Common Runtime Error Types
| Error type | Meaning | Example |
|---|---|---|
ReferenceError | Accessing a variable that cannot be resolved | Using an undeclared variable |
TypeError | Performing an invalid operation on a value | Reading a property of null |
RangeError | Using a value outside an allowed range | Creating an array with an invalid length |
URIError | Using an invalid URI encoding or decoding operation | Calling decodeURIComponent() with malformed encoding |
These built-in error types help developers identify the kind of failure that occurred.
Logical Errors in JavaScript
A logical error occurs when a program executes without necessarily throwing an exception but produces an incorrect result.
These errors are usually caused by mistakes in the program’s logic, conditions, calculations, or algorithm.
Example of a Logical Error
Suppose you want to calculate the average of two numbers.
const a = 20;
const b = 30;
const average = a + b / 2;
console.log(average);
Output:
35
The program executes successfully, but the calculation is incorrect because division has higher precedence than addition.
The correct formula is:
const a = 20;
const b = 30;
const average = (a + b) / 2;
console.log(average);
Output:
25
How to Find Logical Errors
You can identify logical errors by:
- Checking the expected output against the actual output.
- Testing different input values.
- Using
console.log()to inspect intermediate results. - Using browser developer tools to set breakpoints.
- Reviewing conditions, calculations, and operator precedence.
Unlike ordinary runtime exceptions, logical errors are not automatically detected by JavaScript’s error-handling mechanism.
The try Statement in JavaScript
The try statement lets you define a block of code that may throw an exception. If a catchable exception occurs inside that block, JavaScript transfers control to the corresponding catch block.
Syntax
try {
// Code that may throw an error
} catch (error) {
// Handle the error
}
The try block contains the statements you want to protect. The catch block receives the thrown value when an exception is caught.
Example of try
try {
const result = 10 / 2;
console.log(result);
} catch (error) {
console.log("An error occurred");
}
Output:
5
Because no exception occurs, the catch block does not execute.
Example When an Error Occurs
try {
console.log(userName);
} catch (error) {
console.log("An error occurred");
}
Output:
An error occurred
In this example, userName has not been declared, so evaluating it throws a ReferenceError. The catch block handles that exception.
The try statement does not automatically fix an error. It allows your program to respond to an exception and decide what should happen next.
The catch Statement in JavaScript
The catch statement handles an exception thrown from the associated try block.
It receives the thrown value through its parameter, commonly named error.
Syntax
try {
// Code that may throw an error
} catch (error) {
// Handle the error
}
Example of catch
try {
const user = null;
console.log(user.name);
} catch (error) {
console.log(error.name);
console.log(error.message);
}
Output:
TypeError
Cannot read properties of null (reading 'name')
The error.name property identifies the error type, while error.message describes the problem.
Exact message text can differ between JavaScript engines.
Handling Different Errors
You can inspect the error type and respond accordingly.
try {
JSON.parse("{name: 'Karim'}");
} catch (error) {
if (error instanceof SyntaxError) {
console.log("Invalid JSON format");
} else {
console.log("Unexpected error");
}
}
Output:
Invalid JSON format
The input is not valid JSON because property names and string values must use double quotation marks.
A valid JSON string would be:
const data = JSON.parse('{"name": "Karim"}');
console.log(data.name);
Output:
Karim
What Can the catch Block Receive?
JavaScript allows any value to be thrown, not only instances of Error. Therefore, the caught value is not guaranteed to have name or message properties.
For application code, it is generally better to throw Error objects so that error handling remains consistent.
The finally Statement in JavaScript
The finally block contains code that runs after the try and catch processing completes, whether an exception occurred or not.
It is commonly used for cleanup operations, such as releasing resources or resetting a loading indicator.
Syntax
try {
// Code that may throw an error
} catch (error) {
// Handle the error
} finally {
// Cleanup code
}
The catch block is optional when using try...finally, but try must have at least one of catch or finally.
Example of finally
try {
console.log("Try block executed");
} catch (error) {
console.log("Catch block executed");
} finally {
console.log("Finally block executed");
}
Output:
Try block executed
Finally block executed
No exception occurs, so the catch block is skipped. The finally block still executes.
Example with an Error
try {
console.log("Starting program");
throw new Error("Something went wrong");
} catch (error) {
console.log(error.message);
} finally {
console.log("Program finished");
}
Output:
Starting program
Something went wrong
Program finished
The error is thrown, handled by catch, and followed by the finally block.
When Should You Use finally?
Use finally when an operation needs cleanup regardless of whether it succeeds or fails.
For example:
- Hiding a loading indicator.
- Resetting a temporary application state.
- Releasing a resource after an operation.
- Completing cleanup after an error has been handled.
Remember that finally normally runs when control leaves the try...catch structure, but it is not an absolute guarantee under conditions such as forcibly terminating the process. Also, returning or throwing from finally can override an earlier return value or exception, so avoid doing that unless you specifically intend the behavior.
The throw Statement in JavaScript
The throw statement allows you to create an exception deliberately.
You can use it when a function receives invalid input, a required condition is not satisfied, or an operation cannot continue safely.
Syntax
throw expression;
The expression can be any JavaScript value. However, throwing an Error object is generally recommended because it provides a consistent error type and message.
Example of throw
const age = 15;
if (age < 18) {
throw new Error("You must be at least 18 years old");
}
console.log("Access granted");
Output:
Uncaught Error: You must be at least 18 years old
The exact console formatting may vary. The exception stops the normal execution path unless it is caught by an appropriate handler.
Handling a Thrown Error
const age = 15;
try {
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
The error is caught, so the program can handle the invalid condition without leaving the exception unhandled.
Creating a Reusable Validation Function
function checkAge(age) {
if (age < 18) {
throw new Error("Age must be 18 or older");
}
return "Access granted";
}
try {
console.log(checkAge(20));
console.log(checkAge(16));
} catch (error) {
console.log(error.message);
}
Output:
Access granted
Age must be 18 or older
When checkAge(16) throws an error, execution transfers to the catch block. Any statements remaining in the try block are skipped.
Difference Between try, catch, finally, and throw
These four JavaScript keywords work together, but each has a different purpose.
| Keyword | Purpose |
|---|---|
try | Defines code where exceptions may occur |
catch | Handles an exception from the associated try block |
finally | Runs cleanup code after try and catch processing |
throw | Raises an exception deliberately |
You can combine these keywords to validate data, report problems, and clean up resources.
Using try…catch with JSON.parse()
One practical use of error handling is parsing JSON data. If the supplied text is not valid JSON, JSON.parse() throws a SyntaxError.
const jsonString = '{"name": "Karim", "age": 25}';
try {
const user = JSON.parse(jsonString);
console.log(user.name);
console.log(user.age);
} catch (error) {
console.log("Unable to parse JSON:", error.message);
}
Output:
Karim
25
If the JSON string is invalid, the catch block handles the exception instead.
For example, replacing the input with "{name: Karim}" causes parsing to fail because the string is not valid JSON.
This technique is useful when processing data received from files, storage, or external systems.
Error Handling with Async/Await
Errors can also occur during asynchronous operations. When using async and await, you can use try...catch to handle a rejected promise or an exception thrown while evaluating the awaited expression.
async function getUser() {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users/1"
);
if (!response.ok) {
throw new Error("Unable to fetch user data");
}
const user = await response.json();
console.log(user.name);
} catch (error) {
console.log("Error:", error.message);
}
}
getUser();
Expected behavior: If the request succeeds and returns valid JSON, the program prints the user’s name. If the request fails or an exception occurs, the catch block handles the error.
The response.ok check is important because fetch() generally does not reject solely because the server returns an HTTP error status such as 404 or 500.
To learn more, see JavaScript Async/Await.
Best Practices for JavaScript Error Handling
Follow these practices to make your code easier to maintain and debug.
- Use
try...catcharound operations that can reasonably throw exceptions and that you can handle meaningfully. - Throw
Errorobjects instead of arbitrary strings or numbers. - Provide clear and useful error messages.
- Validate user input before performing important operations.
- Use
finallyfor cleanup tasks that should happen after success or failure. - Avoid empty
catchblocks that silently hide problems. - Do not expose passwords, access tokens, or other sensitive information in error messages.
- Handle rejected promises instead of leaving them unhandled.
- Avoid using
try...catchas a substitute for fixing syntax errors or logical mistakes.
Good error handling makes applications more reliable while helping developers identify and resolve problems.
Common Mistakes in JavaScript Error Handling
Using try Without catch or finally
A try statement must be followed by at least one catch or finally block.
Incorrect:
try {
console.log("Hello");
}
Correct:
try {
console.log("Hello");
} catch (error) {
console.log(error.message);
}
Assuming catch Handles Every Kind of Problem
A catch block handles exceptions that are thrown during the associated execution. It does not automatically detect incorrect business logic, and it cannot catch a syntax error that prevents the containing script from being parsed.
Throwing Plain Strings
Although JavaScript permits throw "Something went wrong", throwing an Error object is generally better.
throw new Error("Something went wrong");
This provides useful properties such as name, message, and, in supporting environments, a stack trace.
Forgetting to Handle Asynchronous Errors
A try...catch block around a promise that is not awaited does not automatically catch a later rejection.
For example:
try {
Promise.reject(new Error("Request failed"));
} catch (error) {
console.log(error.message);
}
The catch block does not handle this rejection because the promise rejection occurs through promise scheduling rather than as a synchronous exception in the try block.
Use promise rejection handling or await inside an asynchronous function:
async function runTask() {
try {
await Promise.reject(new Error("Request failed"));
} catch (error) {
console.log(error.message);
}
}
runTask();
Output:
Request failed
FAQs About JavaScript Error Handling
What is error handling in JavaScript?
Error handling is the process of responding to exceptions and unexpected conditions so that a program can manage failures appropriately.
What is the difference between syntax errors and runtime errors?
Syntax errors occur when code violates JavaScript’s grammar rules. Runtime errors occur during execution when an operation fails, such as accessing a property of null.
What is the purpose of try and catch?
The try block contains code that may throw an exception, while catch handles an exception thrown from that block.
Why do we use finally in JavaScript?
The finally block is useful for cleanup operations that should run after the try and catch processing, regardless of whether an exception occurred.
What does throw do in JavaScript?
The throw statement raises an exception. Developers often use it to report invalid input or conditions that prevent an operation from continuing.
Can try…catch handle logical errors?
Not automatically. Logical errors usually produce incorrect results without throwing exceptions. You need to inspect the logic, test expected results, or use debugging tools to find them.
Can JavaScript catch syntax errors?
An ordinary try...catch cannot catch a syntax error that prevents the containing script from being parsed. However, certain syntax errors in dynamically parsed source code, such as a string passed to eval(), can be caught if parsing and evaluation occur inside the try block. Using eval() is generally unnecessary and should be avoided when safer alternatives exist.
Conclusion
JavaScript error handling helps you build applications that respond to failures more reliably. Syntax errors occur when code violates language rules, runtime errors happen during execution, and logical errors produce incorrect results.
Use try to define code that may throw exceptions, catch to handle those exceptions, finally for cleanup, and throw to raise errors deliberately.
By combining these tools with input validation, promise handling, and clear error messages, you can make your JavaScript applications easier to debug and maintain.