Don't Rescue RuntimeError
I came across some code recently that attempted a long series of steps, and on failure issued a notification. Something functionally similar to:
def complicated_method
# Several calls to things that can raise
rescue RuntimeError => ex
notify_failure(ex)
end
At first instance, this seems appropriate. After all, Ruby defaults to raising a RuntimeError
when not using a more specific exception:
def boom!
raise "Hell"
rescue => ex
ex
end
boom! # => #<RuntimeError: Hell>
There is a subtlety here: Ruby default to raising a RuntimeError
, but defaults to rescuing a StandardError
. A RuntimeError
has a StandardError
as an ancestor, which means that any RuntimeError
will be rescued from a “naked” raise. However, when we specify RuntimeError
as the rescue clause, we might miss a lot of exceptions that we thought we were rescuing, because they don’t have RuntimeError
as an ancestor.
RuntimeError.ancestors # => [RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
ArgumentError.is_a?(RuntimeError) # => false
IOError.is_a?(RuntimeError) # => false
TypeError.is_a?(RuntimeError) # => false
Conclusion
When possible, always rescue specific exceptions, to avoid supressing exception. Failing that, rescue StandardError
, not RuntimeError
. Oh, and don’t rescue Exception
.
Find me on Mastodon at @ylansegal@mastodon.sdf.org,
or by email at ylan@{this top domain}
.