Why Isn't Ruby Rescuing My Exception?
I was really confused yesterday when
rescue refused to catch my exception.
begin user.update # raises a MyApp::Error rescue => error # but was not rescued end
rescue supposed to rescue everything? Actually, no. Without specifying which exception classes to catch,
rescue will only catch exceptions that inherit from
begin rescue end
…is really just short-hand for:
begin rescue StandardError end
Some folks recommend explicitly writing
rescue StandardError whenever you want a plain
rescue. I don’t have a strong opinion, because once you know why Ruby behaves the way it does, you won’t be caught off guard.
Why does Ruby default to only catching exceptions that inherit from
StandardError? Let’s look at some examples from the
Exception class hierarchy.
Events that should stop your program (like the user hitting
ctrl-c in the terminal or
require failing to find a file) inherit directly from
Exception. Problems that might be recoverable (like calling
nil or passing
Time.parse) inherit from
StandardError. This means that our code should almost always inherit from
Sure enough, that was my bug. I changed…
class MyApp::Error < Exception end
class MyApp::Error < StandardError end
…and the error was properly caught!
Just a tip; you can define your own exceptions like this:
MyApp::Error = Class.new(StandardError)
One benefit being no ugly trailing ‘end’. Also, and I know the point was to illustrate the idea, but try to be more specific: Error could be anything, WidgetFailureError is much more descriptive. Then:
WidgetFailureError = Class.new(StandardError)
Nice find though.