try, catch and throw

JavaScript ES2024 · ✓ verified by execution on 2026-08-18

Errors happen. Sometimes they are your fault (like a typo), and sometimes they are outside your control (like a network failure). When a runtime error occurs, JavaScript normally stops executing immediately and crashes the program.

But you can take control of errors using try...catch.

Catching Errors

The try...catch statement is comprised of a try block and either a catch block, a finally block, or both. It prevents your program from crashing by catching exceptions.

Predict the output javascript

Read the code. What exactly will it print? Commit to an answer before you look.

try {
  nonExistentFunction();
} catch (error) {
  console.log('Caught an error!');
}
console.log('Program continues...');
Output
Caught an error!
Program continues...

If the code inside the try block throws an error, execution jumps immediately to the catch block. The program then continues running normally.

The Error Object

Error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions. It provides useful properties like name and message.

javascript
try {
  throw new TypeError('Invalid type');
} catch (error) {
  console.log(error.name);
  console.log(error.message);
}
Output
TypeError
Invalid type

Throwing Your Own Errors

The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won’t be executed), and control will be passed to the first catch block in the call stack.

javascript
function checkAge(age) {
  if (age < 18) {
    throw new Error('Too young!');
  }
  return 'Access granted';
}

try {
  console.log(checkAge(16));
} catch (error) {
  console.log(error.message);
}
Output
Too young!

The Danger of Swallowing Errors

Catching an error and silently ignoring it (swallowing the error) without handling it makes debugging extremely difficult.

javascript
function doTask() {
  try {
    throw new Error('Database disconnected');
  } catch (err) {
    // Empty catch block hides the error
  }
  console.log('Task finished?');
}
doTask();
Output
Task finished?

When you swallow an error, the program continues in an invalid state. You have no idea what failed or why. If you cannot fully recover from an error, it is often better to rethrow it or let the program crash.

javascript
function logError(e) { console.log('Logged:', e.message); }

try {
  try {
    throw new Error('Critical failure');
  } catch (err) {
    logError(err);
    throw err; // rethrow
  }
} catch (outerErr) {
  console.log('Outer catch caught it');
}
Output
Logged: Critical failure
Outer catch caught it

The finally Block

The code in the finally block will always be executed before control flow exits the entire construct, regardless of whether an error was thrown or caught.

javascript · visualize
try {
  throw new Error('Oops');
} catch (err) {
  console.log('Handled');
} finally {
  console.log('Cleaning up');
}
Handled
Cleaning up
try block Error occurs catch block No errors finally block
How control flows through try/catch/finally: an error inside try jumps straight to catch, a clean run skips it entirely, and finally executes on both paths.

Edge Cases

Check yourself

It's good practice to wrap the entire script in a giant try...catch block just to be safe.

Reveal answer

False, it hides specific error locations and catches errors you can't recover from. — This hides the specific location of errors, degrades performance, and often catches errors you have no way of recovering from.

You should always use an empty catch block if you don't want the program to crash.

Reveal answer

False, swallowing errors masks real issues and leaves the app in an invalid state. — Empty catch blocks ('swallowing' errors) mask real issues. If you can't handle the error, it is better to let the program fail loudly or log and rethrow it.

Can try...catch handle asynchronous errors like a rejected Promise or an error in setTimeout?

Reveal answer

No, synchronous try...catch blocks will not catch errors thrown inside a setTimeout or rejected Promise. — A synchronous try...catch block will not catch errors thrown inside a setTimeout callback or a rejected Promise.

What are you allowed to throw in JavaScript?

Reveal answer

Anything (strings, numbers, objects), though Error objects are standard. — You can throw literally anything in JavaScript (strings, numbers, objects), though throwing Error objects is the standard and provides stack traces.

Challenges

Challenge 1 +10 XP

The `JSON.parse` function throws an error if the string is invalid JSON. Use a `try...catch` block to attempt parsing `badJson`. If it fails, log 'Invalid format'.

javascript
  • Test 1 — expects "Invalid format"
Need a hint? (−25% XP)

Put the parsing logic inside the `try { ... }` block, and print 'Invalid format' inside the `catch (error) { ... }` block.

Show solution (0 XP)
const badJson = '{ name: "Alice" }';
try {
  const data = JSON.parse(badJson);
  console.log(data);
} catch (error) {
  console.log('Invalid format');
}

Challenge 2 +15 XP

Create a function `withdraw(amount)` that throws an Error with the message 'Insufficient funds' if amount is greater than 100. Otherwise, return 'Success'.

javascript
  • Test 1 — expects "Insufficient funds"
Need a hint? (−25% XP)

Use `if (amount > 100) { throw new Error(...) }`.

Show solution (0 XP)
function withdraw(amount) {
  if (amount > 100) {
    throw new Error('Insufficient funds');
  }
  return 'Success';
}

try {
  withdraw(150);
} catch (err) {
  console.log(err.message);
}

🐞 Bug Hunt +20 XP

This program tries to calculate a total but swallows an error. Fix it so the error is properly logged or the program fails.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

javascript
  • Test 1 — expects "Disk full\nProcessing complete."
Need a hint? (−25% XP)

Add `console.log(err.message);` to the catch block instead of leaving it empty.

Show solution (0 XP)
function processItems() {
  try {
    throw new Error("Disk full");
  } catch (err) {
    console.log(err.message);
  }
  console.log("Processing complete.");
}
processItems();