Sometimes our Ruby programs throw errors which we don’t have full control over, such as network timeouts. So, we need to catch and handle those errors. To do so, we need to choose an Exception -descended class (or classes) to catch. What’s the right granularity of that class?

Ruby’s Exception class hierarchy starts with Exception . If we try to raise an object that is not an Exception , Ruby complains.

begin raise 1234.0 rescue => error puts error.inspect end

Results in:

#<TypeError: exception class/object expected>

By default, rescue only catches things that are StandardError s. To rescue something that isn’t a StandardError , we have to specify:

begin raise Exception.new rescue Exception => error puts "Correct!" end

Results in:

Correct!

We don’t want to rescue Exception s, however. Exceptions that aren’t StandardError s are reserved for things like Interrupt when we hit Ctrl-C, and NoMemoryError .

Exceptions that are StandardError s are what a normal Ruby program are supposed to use.

In the best-case scenario, we know exactly which error (or errors) can occur. So, we restrict our rescue statement to only the subset of errors that are out of our control:

HTTP_ERRORS = [ EOFError, Errno::ECONNRESET, Errno::EINVAL, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, Timeout::Error ] begin some.http.call rescue *HTTP_ERRORS => error notify_airbrake(error) end

By isolating our rescue statement to a subset of classes, we won’t be overly-greedy and silently fail when something else goes wrong, such as some returning a nil value.

On occasion, that won’t be possible. In those cases, we explicitly use StandardError instead:

begin some.unique.situation rescue StandardError => error notify_airbrake(error) end

If you found this useful, you might also enjoy: