How does try/catch/finally work in JavaScript?

try runs code that might throw; catch handles the error; finally always runs regardless of outcome useful for cleanup.

JavaScript

Overview

`try/catch` is how JavaScript handles runtime errors synchronously. For async code with `async/await`, it works exactly the same way. The `finally` block runs whether or not an error occurred perfect for cleanup logic.

Key Points

  • •`try` wraps the code that might throw an error.
  • •`catch(error)` runs only if an error was thrown; `error` is the Error object (or whatever was thrown).
  • •`finally` always runs even if there's a `return` inside `try` or `catch`.
  • •You can throw any value: `throw new Error("msg")`, `throw 42`, `throw { code: 404 }` but Error objects are best practice.
  • •Use `error.message`, `error.name`, and `error.stack` for debugging. Custom error classes extend `Error`.

Examples

Basic try/catch

javascript
try {
  const data = JSON.parse(invalidJson);
} catch (error) {
  console.error('Parse failed:', error.message);
}

finally for cleanup (e.g. loading state)

javascript
async function fetchData() {
  setLoading(true);
  try {
    const data = await api.get('/users');
    setUsers(data);
  } catch (error) {
    setError(error.message);
  } finally {
    setLoading(false); // always runs, even if catch returns early
  }
}

Throwing and catching custom errors

javascript
class ValidationError extends Error {
  constructor(field, message) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

try {
  if (!email.includes('@')) throw new ValidationError('email', 'Invalid email');
} catch (error) {
  if (error instanceof ValidationError) {
    showFieldError(error.field, error.message);
  } else {
    throw error; // re-throw unexpected errors
  }
}

Pro Tip

Don't catch errors you can't handle. Catching and swallowing an error (`catch {}`) hides bugs. Either handle it meaningfully or re-throw it. A caught error is not a fixed error.