"Never rescue Exception in Ruby!"

Maybe you've heard this before. It's good advice, but it's pretty confusing unless you're already in the know. Let's break this statement down and see what it means.

You probably know that in Ruby, you can rescue exceptions like so:

begin
  do_something()
rescue => e
  puts e # e is an exception object containing info about the error. 
end

And you can rescue specific errors by providing the classname of the error.

begin
  do_something()
rescue ActiveRecord::RecordNotFound => e
  puts e # Only rescues RecordNotFound exceptions, or classes that inherit from RecordNotFound
end

Every type of exception in Ruby is just a class. In the example above, ActiveRecord::RecordNotFound is just the name of a class that follows certain conventions.

This is important because when you rescue RecordNotFound, you also rescue any exceptions that inherit from it.

Why you shouldn't rescue Exception

The problem with rescuing Exception is that it actually rescues every exception that inherits from Exception. Which is....all of them!

That's a problem because there are some exceptions that are used internally by Ruby. They don't have anything to do with your app, and swallowing them will cause bad things to happen.

Here are a few of the big ones:

  • SignalException::Interrupt¬†- If you rescue this, you can't exit your app by hitting control-c.

  • ScriptError::SyntaxError - Swallowing syntax errors means that things like puts("Forgot something) will fail silently.

  • NoMemoryError - Wanna know what happens when your program keeps running after it uses up all the RAM? Me neither.

begin
  do_something()
rescue Exception => e
  # Don't do this. This will swallow every single exception. Nothing gets past it. 
end

I'm guessing that you don't really want to swallow any of these system-level exceptions. You only want to catch all of your application level errors. The exceptions caused YOUR code.

Luckily, there's an easy way to to this.

Rescue StandardError Instead

All of the exceptions that you should care about inherit from StandardError. These are our old friends:

  • NoMethodError - raised when you try to invoke a method that doesn't exist

  • TypeError - caused by things like 1 + ""

  • RuntimeError -¬†who could forget good old RuntimeError?

To rescue errors like these, you'll want to rescue StandardError. You COULD do it by writing something like this:

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end

But Ruby has made it much easier for use.

When you don't specify an exception class at all, ruby assumes you mean StandardError. So the code below is identical to the above code:

begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
end

Custom Exceptions Should Inherit from StandardError

So what does this mean for you if you're creating your own custom exceptions?

It means you should always inherit from StandardError, and NEVER from Exception. Inheriting from Exception is bad because it breaks the expected behavior of rescue. People will think they're rescuing all application-level errors but yours will just sail on through.

class SomethingBad < StandardError
end

raise SomethingBad

The Exception Tree

Since Ruby's exceptions are implemented in a class heirarchy, it can be helpful to see it laid out. Below is a list of exception classes that ship with Ruby's standard library. Third-party gems like rails will add additional exception classes to this chart, but they will all inherit from some class on this list.

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal