Error Handling
Errors are not signs of failure — they are signals. Learn everything from basic try/catch to advanced real-world error architectures used in production apps.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:
- Download Node.js to run JavaScript on your computer
- Use your browser's Developer Console (Press F12) to test code snippets
- Create a .html file with <script> tags and open it in your browser
Why Error Handling Matters
- Your app crashes suddenly
- Users lose progress
- Data becomes corrupted
- Security becomes weaker
- Debugging becomes 10× harder
JavaScript gives you extremely powerful tools to handle, detect, filter, categorize, and recover from errors — synchronously AND asynchronously.
1. What Is an Error in JavaScript?
An error occurs when JavaScript cannot complete an operation. Examples:
- Trying to use an undefined variable
- Calling a function that doesn't exist
- Invalid API responses
- Network failures
- Logic errors in your code
- Unexpected data formats
By default, errors stop execution. Your job is to catch, interpret, and recover from them.
2. Try...Catch — The Foundation
- try runs your potentially-dangerous code
- catch receives the error if thrown
- finally ALWAYS runs (cleanup, closing files, removing loaders, etc.)
3. Throwing Your Own Errors
JavaScript allows you to create and throw your own errors:
- You can prevent further execution
- You can communicate clearly what went wrong
- You can enforce data validation
- You create predictable behaviour
4. Built-In Error Types
5. Using Error Names to Handle Smartly
This lets you create fine-grained error logic.
6. Error Handling in Asynchronous Code
- Real-world JavaScript is 70% async
- Network issues happen
- Users have slow internet
- Data can be malformed
7. Re-Throwing Errors
Sometimes you want to catch an error, log it, then pass it upward:
- Logging errors
- Adding context
- Creating layered architecture
8. Creating Custom Error Classes
- Cleaner error organization
- More predictable logic
- Easier debugging
- Perfect for large apps
9. Nested Try...Catch Blocks
- Parsing inside processing
- Handling multiple API calls
- Running multi-stage operations
10. Best Practices for Error Handling
11. Real-World Example — Payment Processing
12. Real-World Example — Robust API Fetching
Now your UI doesn't crash when the API fails — it gracefully recovers.
13. Real-World Example — Form Validation
14. Advanced Async Error Handling
Asynchronous code is where 90% of real production errors happen.
- APIs timeout
- Backend services go down
- Internet drops
- JSON parsing fails
- Unexpected response shape
- Race conditions
- Authentication tokens expire
You MUST master async error strategies to build real-world websites, apps, and SaaS systems.
15. Fetch Errors Aren't Always "Errors"
- Network down
- Domain unreachable
- CORS failures
- Request blocked
⚠️ It does NOT throw errors for bad HTTP codes (404, 500, 403, 429)
Without this check, your code will behave like everything is fine when it absolutely isn't.
16. Retry Logic with Exponential Backoff
Real-world apps must recover from errors gracefully:
Retries at: 200ms → 400ms → 600ms. This is used by Google, AWS, Netflix, Stripe, PayPal.
17. Defensive Programming
Defensive programming = writing code that assumes things will go wrong.
18. Global Error Handling
Most frameworks implement a global error handler:
19. Production-Grade Error Handler
- Cancellation
- Status errors
- Network errors
- JSON parsing
20. Common JavaScript Error Scenarios
- ✔ JSON parsing failure
- ✔ Network offline
- ✔ Missing properties
- ✔ Undefined variable
- ✔ Null access
- ✔ Wrong type
- ✔ Not catching async error
- ✔ Silent Promise rejection
- ✔ Invalid function argument
- ✔ Race condition
You will encounter these daily in real development.
🎯 Practice Projects for Mastery
- Validate numbers
- Throw errors for wrong input
- Catch and display friendly messages
- Try/catch around each operation
Build a function: safeFetch(url, retries = 3)
- Throw on bad HTTP codes
- Distinguish network vs HTTP error
- Return JSON or fallback
- Use multiple custom error classes
- Validate email, password, username
- Show UI messages
- Demonstrate window.onerror
- Demonstrate window.onunhandledrejection
📋 Quick Reference — Error Handling
Method
Purpose
try...catch
Catch errors in a block of code
throw
Manually trigger an error
finally
Run code regardless of outcome
Error Object
Has .message and .stack
Custom Error
class MyError extends Error
Lesson 10 Complete — Error Handling!
You've mastered the art of writing robust code that handles failure gracefully. This separates amateur code from professional software.
Up next: Closures & Scope — diving deep into advanced JavaScript concepts! 🧠
Practice quiz
In a try/catch/finally block, when does the finally block run?
- Only when an error is thrown
- Only when no error is thrown
- Always, regardless of the outcome
- Never, it is optional
Answer: Always, regardless of the outcome. finally always runs, making it ideal for cleanup like closing connections or removing loaders.
Which keyword do you use to manually trigger an error?
- throw
- raise
- error
- catch
Answer: throw. throw manually triggers an error, for example throw new Error('Cannot divide by zero').
Which error type is thrown by null.toUpperCase()?
- ReferenceError
- SyntaxError
- RangeError
- TypeError
Answer: TypeError. Calling a method on null is an incorrect data type operation, which throws a TypeError.
Which error type occurs when you use a variable that was never declared?
- TypeError
- ReferenceError
- RangeError
- URIError
Answer: ReferenceError. Referencing an undeclared variable throws a ReferenceError.
How do you create a custom error class?
- class MyError extends Error { }
- function MyError()
- new CustomError()
- Error.create('My')
Answer: class MyError extends Error { }. Custom errors extend the built-in Error class, e.g. class ValidationError extends Error.
Does fetch() throw an error for HTTP status codes like 404 or 500?
- Yes, always
- Only for 500
- No, you must check res.ok yourself
- Only in strict mode
Answer: No, you must check res.ok yourself. fetch only rejects for network-level failures; you must check res.ok for bad HTTP status codes.
What does 're-throwing' an error mean?
- Catching an error and ignoring it
- Catching an error, handling it locally, then throwing it again to pass it upward
- Throwing two errors at once
- Converting an error to a string
Answer: Catching an error, handling it locally, then throwing it again to pass it upward. Re-throwing lets you log or add context locally, then pass the error up with throw err.
How can you handle errors in async/await code?
- With a .then() only
- Errors cannot be caught in async code
- With window.onerror only
- By wrapping the awaited calls in try/catch
Answer: By wrapping the awaited calls in try/catch. async/await uses ordinary try/catch around the awaited operations to catch failures.
In an outer/inner nested try/catch, where is an error thrown in the inner try caught first?
- The outer catch
- The inner catch
- Both simultaneously
- Neither
Answer: The inner catch. The nearest enclosing catch handles it first; the inner catch catches the inner error.
Which is a recommended error-handling best practice from the lesson?
- Show database stack traces to users
- Ignore async errors
- Use specific error messages and don't leak sensitive info
- Fail silently
Answer: Use specific error messages and don't leak sensitive info. Use clear, specific messages, handle async errors, and never leak sensitive details to users.