Skip to main content

Command Palette

Search for a command to run...

Error Handling in JavaScript: Try, Catch, Finally

Updated
5 min read
Error Handling in JavaScript: Try, Catch, Finally

Code fatega, tension mat lo — sambhalna aana chahiye

JavaScript runs. But sometimes it crashes.

Your code breaks. App stops. User sees blank screen.

That's bad.

But what if you could catch the error and handle it gracefully?

Enter try, catch, finally.


The Problem: Code That Crashes

const user = null;
console.log(user.name); // TypeError: Cannot read property 'name' of null

Your entire app stops. Everything after this line? Dead.

One small mistake, whole app down.


What Are Errors in JavaScript?

Errors happen when JavaScript can't execute code properly.

Common errors:

Error Type When it happens
ReferenceError Variable doesn't exist
TypeError Wrong type (null.name)
SyntaxError Wrong syntax (missing })
RangeError Value out of range (array length -1)
// ReferenceError
console.log(unknownVar);

// TypeError
[1, 2, 3].map(null);

// SyntaxError (won't even run)
const a = {;

// RangeError
const arr = new Array(-1);

What is Try...Catch?

Try = try to run risky code. Catch = if error happens, run this instead.

try {
  const user = null;
  console.log(user.name); // Error happens here
  console.log("This won't run");
} catch (error) {
  console.log("Something went wrong:", error.message);
}

console.log("App continues...");

// Output:
// Something went wrong: Cannot read property 'name' of null
// App continues...

App didn't crash. It kept running.


Try...Catch Flow Diagram


The Catch Error Object

Catch gives you an error object with useful info:

try {
  throw new Error("Something bad happened");
} catch (err) {
  console.log(err.name);     // "Error"
  console.log(err.message);  // "Something bad happened"
  console.log(err.stack);    // Full stack trace
}

Finally Block — Jo Bhi Ho, Chalega

Finally runs every time — whether error happened or not.

try {
  console.log("Trying...");
  // No error
} catch (err) {
  console.log("Catch:", err);
} finally {
  console.log("Finally: Cleanup work here");
}

// Output:
// Trying...
// Finally: Cleanup work here

With error:

try {
  console.log("Trying...");
  throw new Error("Oops");
} catch (err) {
  console.log("Catch:", err.message);
} finally {
  console.log("Finally: Still runs");
}

// Output:
// Trying...
// Catch: Oops
// Finally: Still runs

Try → Catch → Finally Execution Flow


Throwing Custom Errors

You can create your own errors with throw.

function divide(a, b) {
  if (b === 0) {
    throw new Error("Division by zero is not allowed");
  }
  return a / b;
}

try {
  const result = divide(10, 0);
  console.log(result);
} catch (err) {
  console.log("Error:", err.message);
}

// Output:
// Error: Division by zero is not allowed

Custom Error Types

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

try {
  const age = -5;
  if (age < 0) {
    throw new ValidationError("Age cannot be negative");
  }
} catch (err) {
  if (err instanceof ValidationError) {
    console.log("Validation:", err.message);
  } else {
    console.log("Other error:", err);
  }
}

Why Error Handling Matters

Without error handling With error handling
App crashes App continues
User sees blank screen User sees friendly message
Hard to debug Clear error logs
Bad user experience Graceful failure

Example: API call with vs without try-catch

// Without try-catch (bad)
async function getUser() {
  const response = await fetch("/api/user");
  const data = await response.json();
  console.log(data.name);
}
// If network fails → entire app crashes

// With try-catch (good)
async function getUser() {
  try {
    const response = await fetch("/api/user");
    const data = await response.json();
    console.log(data.name);
  } catch (error) {
    console.log("Failed to load user. Please try again.");
    // Show friendly message to user
  }
}

Common Mistakes

Mistake 1: Not catching async errors

// ❌ Try-catch won't catch async errors directly
try {
  setTimeout(() => {
    throw new Error("Oops"); // This crashes the app
  }, 1000);
} catch (err) {
  console.log("Caught:", err); // Never runs
}

// ✅ Catch inside the async callback
setTimeout(() => {
  try {
    throw new Error("Oops");
  } catch (err) {
    console.log("Caught:", err.message);
  }
}, 1000);

Mistake 2: Empty catch block

try {
  riskyCode();
} catch (err) {
  // Empty — bad! You'll never know what happened
}

Always log or handle the error.


Real-World Examples

Example 1: Form validation

function validateForm(formData) {
  try {
    if (!formData.name) throw new Error("Name is required");
    if (formData.age < 18) throw new Error("Must be 18+");
    if (!formData.email.includes("@")) throw new Error("Invalid email");
    
    console.log("Form submitted");
    return true;
  } catch (err) {
    alert(err.message);
    return false;
  }
}

Example 2: JSON parsing

function parseUserData(jsonString) {
  try {
    const user = JSON.parse(jsonString);
    console.log("User:", user);
    return user;
  } catch (err) {
    console.log("Invalid JSON received");
    return null;
  }
}

parseUserData('{"name":"Batman"}'); // Works
parseUserData("not json"); // Invalid JSON received

Example 3: File reading (Node.js style)

const fs = require('fs');

try {
  const data = fs.readFileSync('file.txt', 'utf8');
  console.log(data);
} catch (err) {
  console.log("File not found. Creating default...");
  fs.writeFileSync('file.txt', 'default content');
}

Try-Catch Performance Note

Try-catch has a small performance cost. Don't wrap every line.

Use where errors are likely:

  • API calls

  • JSON parsing

  • User input validation

  • File operations

Don't use where errors are unlikely:

  • Simple math

  • String concatenation


Final Thought

Code fatega. That's normal.
But app crash nahi hona chahiye.
Try-catch let's you fail gracefully — show friendly message, log the error, keep the app running.

Finally block is for cleanup.

Throw your own errors for validation.