JavaScript Try/Catch Synchronous Error Handling

Home » JavaScript Tutorial » JavaScript Control Flow and Collections » JavaScript Try/Catch Synchronous Error Handling

In programming, errors (also called Exceptions) are inevitable. A user might enter the wrong data type, or a variable you expect to exist might be missing. Without error handling, these issues cause your program to “crash” or stop executing entirely.

The try...catch statement allows you to “trap” these errors, handle them gracefully, and keep your application running.

The structure consists of a try block where you place the code you want to run, and a catch block that executes only if an error occurs in the try block.

console.log("Program Started...");
// const someUndefinedVariable = 2; (enable for try block w/out error)

try {
  // Code that might throw an error
  // 'someUndefinedVariable' does not exist, so JS creates an Error Object here
  const result = 10 / someUndefinedVariable; 
  
  // 🛑 GUARD: This line will NEVER run if the error occurs above.
  console.log("This success message will be skipped.");

} catch (error) {
  // 🛡️ SAFETY NET: Code to handle the error
  console.log("An error occurred!");
  console.log("Error Message: " + error.message);
}

console.log("Program continues to run...");

/* Output: 
Program Started...
An error occurred!
Error Message: someUndefinedVariable is not defined
Program continues to run...
*/
JavaScript

When an error occurs, JavaScript generates an Error Object and passes it into the catch block (usually named error or e). You might wonder: Where does that error variable come from?

When JavaScript encounters a crash, it automatically performs three steps in milliseconds:

  1. Pauses execution.
  2. Constructs a new object using the Error class (populating it with details like name, message, and stack).
  3. Throws this object into your catch block.

This object usually contains:

  • error.name: The type of error (e.g., ReferenceError, SyntaxError).
  • error.message: A human-readable string describing the problem.
  • error.stack: A technical trace of where the error happened in the file.

Examples of different Error types that can be caught or generated via Try/Catch:

const num = 1.23;
try {
	// Note: the code stops executing in the try block at the first error.
	// Change commenting // to see individual error types in console.
	console.log(noVariableSet); // ReferenceError
	//console.log(num.toUpperCase()); // TypeError
	//console.log(num.toFixed(101)); // RangeError (you can only have 100 decimal places)
	//console.log(JSON.parse('{"name":"Bob}')); // SyntaxError (missing " after Bob")
	//decodeURI("%") // URIError (Uniform Resource Identifier)
	//throw new Error("My custom error message."); // Custom Error object message
	
} catch (myError) {
  console.log("Error Name: " + myError.name)
  console.log("Error Message: " + myError.message);
  console.log("Error Stack: " + myError.stack);
}

/* Output: 
Error Name: ReferenceError
Error Message: noVariableSet is not defined
Error Stack: ReferenceError: noVariableSet is not defined
    at index.html:14:14
*/
JavaScript

One of the most common uses for synchronous try/catch is handling data from external sources, specifically JSON.parse(). If the data is malformed, JSON.parse() will crash your app immediately. You cannot prevent this with an if statement; you must use try/catch.

const badData = '{"name": "John", "age": 30, }'; // ❌ Syntax Error (trailing comma)
try {
	const user = JSON.parse(badData);
	console.log("User parsed successfully:", user.name);
} catch (e) {
	console.log("⚠️ Data corrupted. Using default guest user.");
	console.log("Error:", e.name);
	console.log("Technical reason:", e.message);
}
/* Output:
⚠️ Data corrupted. Using default guest user.
Error: SyntaxError
Technical reason: Expected double-quoted property name in JSON at position 28 (line 1 column 29)
(The technical reason above may vary by browser)
*/
JavaScript

The finally block is a special section that runs no matter what, regardless of whether an error was caught or not. It is often used for “cleanup” tasks, such as hiding a loading spinner or closing a database connection. The finally block can ensure that code critical for the program’s state runs, even if an exception occurs.

try {
	console.log(undefinedVar);
	//console.log("Try Block");	
} catch (error) {
	console.log("Catch Error: " + error.message + " " + error.name);
} finally {
	console.log("This is the finally block (always runs).");
}
/* Output:
Catch Error: undefinedVar is not defined ReferenceError
This is the finally block (always runs).
*/
JavaScript

Sometimes, code is technically valid JavaScript but “wrong” for your specific application logic (e.g., a user enters a negative age). You can manually trigger the catch block using the throw keyword.

When you throw, you are the one creating the Error object and defining the .message property.

function checkAge(age) {
  if (age < 0) {
    // Manually trigger an error with a custom message
    throw new Error("Age cannot be negative!");
  }
  return "Age is valid.";
}

try {
  console.log(checkAge(-5)); // Passing negative value to the CheckAge function.
} catch (e) {
  console.log("Validation Failed: " + e.message); // Custom Error message.
}
// Output: Validation Failed: Age cannot be negative!
JavaScript
  • Synchronous Only: The standard try...catch block does not catch errors in asynchronous code (like setTimeout or network requests). Those require different techniques (Promises/Async-Await) which are covered in a later module.
  • Control Flow vs. Error Handling: Do not use try/catch for simple logic.
    • Bad: try { return arr[0] } catch { return null } (Use an if statement).
    • Good: try { JSON.parse(data) } catch { return null } (Because parsing cannot be checked with if).
  • Silent Failures: Avoid empty catch blocks (catch (e) {}). If you “swallow” the error without logging it, you will have a very hard time debugging your code later.

In conclusion: the try…catch statement synchronously executes a block of code and provides a mechanism to elegantly handle and recover from any exceptions (errors) that occur within that block.