Lab 07: Error Handling

🎯 Objective

Master JavaScript error handling — built-in error types, custom errors, try/catch/finally, error propagation, and defensive programming.

📚 Background

JavaScript has 8 built-in error types (TypeError, RangeError, SyntaxError, etc.) plus the base Error class. Unlike Python, JavaScript doesn't have a strong exception hierarchy convention — but building one with custom error classes dramatically improves debuggability. Proper error handling is what separates hobby projects from production systems.

⏱️ Estimated Time

30 minutes

📋 Prerequisites

  • Lab 6: Promises & Async/Await

🛠️ Tools Used

  • Node.js 20

🔬 Lab Instructions

Step 1: Built-in Error Types

📸 Verified Output:

Step 2: Custom Error Classes

📸 Verified Output:

Step 3: try/catch/finally

📸 Verified Output:

Step 4: Error Propagation

📸 Verified Output:

Step 5: Async Error Handling

📸 Verified Output:

Step 6: Global Error Handlers

📸 Verified Output:

Step 7: Input Validation Pattern

📸 Verified Output:

Step 8: Result Type Pattern

📸 Verified Output:

✅ Verification

Expected output:

🚨 Common Mistakes

  1. Empty catch blocks: catch (e) {} silently ignores errors — always at minimum log them.

  2. throw "string": Throw Error objects, not strings — they have .message, .stack, .name.

  3. Forgetting async error handling: async fn().then() without .catch() creates unhandled rejections.

  4. Catching too broadly: Catch specific types where possible; re-throw unknown errors.

  5. Using finally for control flow: finally runs even if catch re-throws — don't use return in finally.

📝 Summary

  • 8 built-in types: Error, TypeError, RangeError, ReferenceError, SyntaxError, URIError, EvalError, AggregateError

  • Extend Error for domain-specific types; set this.name = this.constructor.name

  • try/catch/finallyfinally always runs; ideal for cleanup

  • Async: use try/catch in async functions; .catch() on promises

  • Global handlers: process.on("unhandledRejection"), process.on("uncaughtException")

  • Result pattern: Result.ok(value) / Result.err(error) avoids throw/catch overhead

🔗 Further Reading

Last updated