Logo

Why is it bad style to `rescue Exception => e` in Ruby?

Rescuing exceptions in Ruby is a common practice that helps you gracefully handle errors and maintain application stability. However, using rescue Exception => e is widely considered bad style, as it can lead to problematic behavior and make debugging your code much harder. In this post, we’ll discuss why you should avoid rescuing Exception directly and what best practices to follow instead.

The Basics of Exception Handling in Ruby

Ruby’s exception handling revolves around the begin … rescue … end construct. When an error occurs (an “exception” is raised), Ruby searches for a matching rescue clause. If it finds a match, it executes the rescue block; if not, the exception “bubbles up” until it’s either handled or the application terminates.

A standard usage pattern looks like this:

begin # Code that might raise an error rescue SomeSpecificError => e # Handle this specific error rescue StandardError => e # Handle generic errors end

By default, when you write rescue without specifying an exception class, Ruby actually rescues StandardError and its subclasses. This is usually enough for most application-level errors, but you can add more specific exceptions depending on the situation.

Why Is rescue Exception => e Bad Style?

  1. Overly Broad Scope
    The Exception class is the root of Ruby’s exception hierarchy. This means rescue Exception => e catches everything, including low-level system exceptions like NoMemoryError, SignalException, or SystemExit. Catching these can prevent your program from shutting down gracefully or from handling critical errors properly.

  2. Suppresses Critical Errors
    Errors like Interrupt (triggered by Ctrl+C) and SystemExit (triggered by the exit method) are also subclasses of Exception. If your code rescues them, you may accidentally prevent your application from terminating when it should, creating confusing or even dangerous situations.

  3. Harder Debugging
    When every exception is rescued indiscriminately, legitimate bugs may be swallowed silently, making it incredibly difficult to identify the root cause. The application might continue running in an inconsistent state, resulting in more obscure errors later.

  4. Blocks Programmatic Exit
    By catching exceptions like SystemExit, your script might ignore user-initiated termination (like killing a process), forcing you to rely on more brute-force measures (like kill -9) and causing frustration during development or deployment.

Preferred Best Practices for Exception Handling

  1. Rescue Specific Exceptions
    Instead of rescuing Exception, rescue the exceptions you actually expect:

    begin # Risky operation rescue IOError => e # Handle file IO errors rescue Net::ReadTimeout => e # Handle network timeouts rescue StandardError => e # Fallback for all other general errors end

    This approach gives you fine-grained control and ensures critical errors are not swallowed.

  2. Rescue StandardError for Generic Cases
    If you’re unsure which exceptions might occur, rescuing StandardError is a better choice than rescuing Exception. StandardError covers most of the errors you’d encounter in normal application code without capturing vital system-level exceptions.

  3. Log Exceptions
    Whether you’re rescuing a specific error or StandardError, always log the exception message and backtrace. This will help you debug quickly:

    rescue StandardError => e logger.error("Error encountered: #{e.message}\n#{e.backtrace.join("\n")}") end
  4. Re-raise Critical Exceptions
    If you must catch broad exceptions, consider selectively re-raising critical ones:

    rescue Exception => e raise if [SystemExit, SignalException, NoMemoryError].include?(e.class) # handle everything else end
  5. Fail Fast Philosophy
    Sometimes, you want your application to fail fast instead of handling every possible exception. This prevents inconsistent states and makes it more obvious when a critical error occurs. Use specific rescue blocks only for recoverable scenarios.

Level Up Your Ruby and System Design Skills

Proper error handling is just one piece of writing robust and maintainable code. If you’re aiming to improve your coding and systems design expertise, consider these courses from DesignGurus.io:

  • Grokking the Coding Interview: Patterns for Coding Questions
    This course teaches you the essential coding patterns used in interviews at top tech companies, helping you ace algorithmic questions and write cleaner code in any language (including Ruby).

  • Grokking the System Design Interview
    For mid-to-senior engineers looking to build and scale large software systems, this course covers distributed systems, microservices, and design fundamentals—knowledge you’ll need when working on complex, fault-tolerant applications.

If you want hands-on guidance and real-time feedback, check out the Coding Mock Interview and System Design Mock Interview sessions offered by DesignGurus.io. Ex-FAANG engineers can help you pinpoint weak spots and accelerate your learning.

Conclusion

Using rescue Exception => e in Ruby is considered bad style because it indiscriminately captures all exceptions, including critical system-level ones that control program flow and safe shutdowns. Instead, rescue more specific errors or StandardError to keep your error handling targeted and transparent. By adopting these best practices, you’ll write safer, more maintainable Ruby code that’s easier to debug and extend over time.

CONTRIBUTOR
TechGrind