JavaScript: Error Handling

Learn how to catch, throw, and recover from errors to write more robust JavaScript programs.

Types of Errors

JavaScript errors fall into three categories. Knowing the type helps you locate and fix the problem faster.

Three Error Categories

Each error type has a different cause and a different fix strategy.

  • Syntax error: broken grammar the parser catches before running (missing bracket, typo in keyword)
  • Runtime error: valid syntax that crashes during execution (calling undefined, dividing when value is missing)
  • Logical error: code runs fine but produces the wrong result (off-by-one, wrong operator)

Error Types in Action

Runtime and logical errors: the two you will debug most often.

try...catch Block

Wrap risky code in a try block. If an error is thrown, execution jumps to the catch block instead of crashing.

try...catch

The safest way to handle code that might fail at runtime.

  • try block: contains the code that might throw
  • catch(error): receives the Error object when something goes wrong
  • Code after a throw inside try is skipped; execution continues after the catch
  • Only catches runtime errors, not syntax errors (those stop the script from loading)

try...catch Example

Safely parse user-supplied JSON without crashing.

throw Statement

Use throw to raise your own errors when inputs or conditions are invalid.

throw

You can throw any value, but throwing an Error object gives you a stack trace.

  • Always throw new Error("message") rather than a plain string
  • Throwing stops the current function and unwinds the call stack
  • The thrown value becomes the error argument in the nearest catch block

Custom throw

Guard a function against invalid input and give a clear error message.

finally Block

Code inside finally always runs, whether the try succeeded or an error was caught. Use it for cleanup (closing connections, hiding spinners).

finally

Guarantees cleanup code runs regardless of success or failure.

  • Runs after try and catch, no matter what happened
  • Ideal for: hiding loading spinners, closing files, releasing locks
  • Runs even if catch re-throws the error

finally Example

The loading indicator is hidden whether the fetch succeeded or failed.

Error Object

When you catch an error, the caught value is an Error object with useful built-in properties.

Error Properties

Three properties give you the full picture of what went wrong.

  • name: the error type, e.g. "TypeError", "RangeError"
  • message: the human-readable description you passed to Error()
  • stack: a string showing the call stack at the point of the throw (great for debugging)

Inspecting the Error Object

Read name, message, and stack to understand what went wrong.

Custom Errors

Extend the built-in Error class to create domain-specific error types you can identify with instanceof.

Custom Error Classes

Subclassing Error lets you distinguish different failure modes in one catch block.

  • Call super(message) inside the constructor to set the message
  • Set this.name to your class name so the stack trace shows it correctly
  • Use instanceof in catch to route different errors to different handlers

Custom Error Example

Create a ValidationError class and handle it specifically in catch.

Handling Async Errors

Errors inside async functions must be caught with try...catch around each await, or with.catch() on the returned Promise.

Async Error Handling

Unhandled Promise rejections will crash Node.js and log warnings in browsers.

  • Wrap await inside try...catch just like synchronous code
  • A rejected Promise that is not caught becomes an unhandled rejection
  • You can also chain .catch() on any Promise: fetch(url).catch(err => ...)

Async try...catch

Handle fetch errors with try...catch around await or .catch() on the Promise.

Debugging Techniques

Good debugging skills let you find and fix errors faster. The browser DevTools and a few habits go a long way.

Debugging Toolkit

Use these techniques to locate bugs before reaching for try...catch.

  • console.log(): print values at key points to trace data flow
  • debugger: keyword that pauses execution in DevTools when the panel is open
  • DevTools breakpoints: click a line number in the Sources panel to pause there
  • Step through: use Step Over / Step Into in DevTools to follow code line by line
  • Read the stack trace in the console: the top line shows exactly where the error originated

Debugging with console.log and debugger

Trace values at each step to find where they go wrong.

Console Methods

The console object has several methods beyond log that make debugging clearer.

Useful Console Methods

Each method has a distinct visual style in the browser console.

  • console.log(): general output
  • console.error(): red error output with a stack trace
  • console.warn(): yellow warning output
  • console.table(): renders an array of objects as a formatted table
  • console.group() / groupEnd(): collapses related logs into a labeled group

Console Methods

Use the right method so output is easy to scan in the DevTools console.

MethodStyle in ConsoleBest Use
console.log()Default textGeneral debugging output
console.error()Red with stack traceLogging caught errors
console.warn()Yellow triangleDeprecation or misuse warnings
console.table()Formatted gridArrays of objects
console.group()Collapsible blockGrouping related logs together

Knowledge Check

1. Which type of error occurs when you write code that violates the language grammar rules?

2. What does the finally block do?

3. How do you create and throw a custom error message?

4. Which property of an Error object contains the human-readable description?

5. How do you handle errors in an async/await function?

6. Which console method displays data as a formatted table?

7. What is a logical error?