GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS

Written by thoughtbot

Rescue StandardError, Not Exception

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?

The rescued class must descend from Exception

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>

The default is StandardError

By default, rescue only catches things that are StandardErrors. 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!

Rescuing Exceptions is not idiomatic

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

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

Best-case scenario

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.

When that’s not possible

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

What’s next?

If you found this useful, you might also enjoy: