Mixx’s Engine Room - Stoking the fires at Mixx

Return to Mixx

Ruby tidbit: When rescue doesn’t

Posted by Bill on July 31st, 2008

I learned a valuable lesson this morning, and I thought I’d share it with you. To deal with error conditions, Ruby includes, as do other languages, exception handling. This allows you to put all your code that might generate one or more errors in a block, and deal with any errors that do occur in another block. Far preferable to days of old when we had to check the return value of any call that may generate an error, and deal with it on the spot, each in unique fashion. Exception handling is much cleaner and more manageable:

begin
# Do stuff that may fail here
rescue
# Deal with those failures here
end

Most articles dealing with Ruby exception handling will tell you that the way to catch exceptions is with the “rescue” line. But it turns out, that’s only part of the truth. An example done in Ruby’s irb console:

irb(main):001:0> begin
irb(main):002:1* raise "Haha, you missed me!"
irb(main):003:1> rescue
irb(main):004:1> puts "No I didn't!"
irb(main):005:1> end
No I didn't!

So far so good. But now watch this:

irb(main):006:0> begin
irb(main):007:1* raise Exception.new("Haha, you missed me!")
irb(main):008:1> rescue
irb(main):009:1> puts "No I didn't!"
irb(main):010:1> end
(irb):7:in `irb_binding': Haha, you missed me! (Exception)

Woops! In that case, rescue really did miss it. But why? Doesn’t “rescue” mean rescue everything? I was surprised to find out that it doesn’t. One more example should clear things up:

irb(main):016:0> begin
irb(main):017:1* raise "Better luck next time!"
irb(main):018:1> rescue => e
irb(main):019:1> puts("I caught a " + e.class.to_s)
irb(main):020:1> end
I caught a RuntimeError
=> nil
irb(main):021:0> begin
irb(main):022:1* raise StandardError.new("Better luck next time!")
irb(main):023:1> rescue => e
irb(main):024:1> puts("I caught a " + e.class.to_s)
irb(main):025:1> end
I caught a StandardError
=> nil
irb(main):026:0> begin
irb(main):027:1* raise Exception.new("Better luck next time!")
irb(main):028:1> rescue => e
irb(main):029:1> puts("I caught a " + e.class.to_s)
irb(main):030:1> end
(irb):27:in `irb_binding': Better luck next time! (Exception)

Ah-ha! So while it seems that “rescue” would be the most generic way of dealing with exceptions of all kinds, it really isn’t. It will catch StandardError (of which RuntimeError is a subclass), but it misses Exception. The most generic exception handler turns to be “rescue Exception”:

begin
# Do stuff here
rescue Exception
# I will catch everything, even stuff that "rescue" misses
end

Lesson learned: unless you know the only thing you might have to deal with is StandardError or one of its subclasses, it’s better to use “rescue Exception” than just “rescue”. Nevermind documents that suggest that “rescue” catches exceptions; that’s true, but misleading - it really only catches certain kinds of them.

Add to Mixx!

7 responses to "Ruby tidbit: When rescue doesn’t"

  1. Matthew M. Boedicker added August 16th, 2008 at 5:37 pm

    Just learned this lesson myself the hard way. Plain “rescue” does not catch Hpricot::ParseError. Different from Python where just “except” will catch everything.

  2. Adam Grant added September 25th, 2008 at 6:32 pm

    Wow. Thanks! I just spent an hour trying to debug an Rspec test in Rails, wondering why raising Exception.new wasn’t being rescued. There must be a good reason for the parent class of all exceptions to not be caught with a standard rescue…

  3. Dan Z added November 7th, 2008 at 6:25 pm

    From the example, one could think, as I did, that the most generic exception handler be “rescue => e”. Your example implied to me that that would catches every kind of exception, while “rescue Exception” would not catch RuntimeError or StandardError. The missing piece of information is that RuntimeError and StandardError are children of Exception, so “rescue Exception” is indeed the most generic handler. Thanks for the article. This was a real shocker for me!

  4. Moiz Raja added December 9th, 2008 at 9:49 am

    Thanks! This was extremely helpful. I was going crazy trying to figure out why my ActiveRecord related exception was not getting caught. When I used rescue Exception I found that it was because my model class had a syntax error.

  5. Ali Anwar added March 23rd, 2009 at 4:59 am

    And I thought my plain rescue was a good catcher. Thanks for the eyes-opening article.

    Rescue Exception, to the rescue..!

  6. Ruby: Just rescue… « Rudimentary Art of Programming & Development added May 13th, 2009 at 11:34 am

    [...] it out the hard way, but luckily this guy found it the hard way [...]

  7. gcoladon added June 29th, 2009 at 6:11 pm

    awesome, thanks for this one. I was really stumped!

Add Your Comment

  • (will not be published)
  • (optional)

© 2010 Recommended Reading, Inc. User-generated content is licensed under a Creative Commons Public Domain license.