HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
3 Topics
Chapter•45 Minutes

Error Handling and Robust Control Flow

Learn how JavaScript errors propagate, how try/catch/finally interact with async code, how custom errors work, and how to design reliable error boundaries.

throw and try/catch

JavaScript uses exceptions for abrupt control flow. throw can throw any value, although throwing an Error object is strongly preferred because it provides a stack trace and standardized error metadata. try/catch intercepts exceptions thrown during execution of the protected block.

Catch blocks should add useful context or recover when appropriate rather than blindly swallowing failures.

Catching an Error
function parseUser(input) {
  try {
    return JSON.parse(input);
  } catch (error) {
    throw new Error('Invalid user payload', { cause: error });
  }
}

try {
  parseUser('{invalid}');
} catch (error) {
  console.error(error.message);
  console.error(error.cause);
}
💡 The original parsing failure is preserved as the cause of a more domain-specific error.
Key Takeaways
  • Prefer throwing Error objects.
  • Use catch blocks to recover or add meaningful context.
  • Error causes can preserve the original failure.
Knowledge Check

What is generally the best thing to throw for an application error?

finally and Cleanup

A finally block executes after the try/catch path regardless of whether the operation succeeds or throws, making it useful for cleanup. Be careful when returning from finally: a return there can override a return or exception from the try/catch block.

Resource Cleanup
let connection;

try {
  connection = openConnection();
  useConnection(connection);
} catch (error) {
  console.error(error);
} finally {
  connection?.close();
}
💡 The finally block provides a reliable place to perform cleanup regardless of success or failure.
Key Takeaways
  • finally is designed for cleanup.
  • Cleanup should happen even when an exception occurs.
  • Avoid returning from finally unless you intentionally want to override control flow.
Knowledge Check

When is finally useful?

Custom Error Classes

Custom error classes allow applications to distinguish categories of failures. Extending Error allows code to use instanceof or other properties to make decisions without parsing human-readable messages.

For example, a REST API might distinguish validation errors, authentication errors, and infrastructure errors.

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

throw new ValidationError('Email is required', 'email');
💡 A custom error class carries structured domain information while retaining normal Error behavior.
Key Takeaways
  • Custom errors make error categories explicit.
  • Structured error properties are better than parsing messages.
  • Error classes can be checked using instanceof.
Knowledge Check

What is a major benefit of custom Error classes?