---
title: Rescue StandardError, Not Exception
teaser:
tags: web,ruby
author: Jon Yurek
published_on: 2013-11-18
---

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 `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!

## Rescuing Exceptions is not idiomatic

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.

## 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:

* [Testing HTTP Errors with Ruby][testing]
* [Using GDB to Inspect a Running Ruby Process][gdb]
* [Exceptional Ruby][exceptional]

[testing]: https://thoughtbot.com/blog/testing-failure/
[gdb]: https://thoughtbot.com/blog/using-gdb-to-inspect-a-running-ruby-process/
[exceptional]: http://exceptionalruby.com/
