Ruby Exceptions And Exception Handling

ExceptionRuby exceptions and error handling is not the most remarkable feature of the Ruby language. Infact, the way Ruby deals with exceptions is strikingly similar to other languages (such as Java etc.). But, I think all the stuff I’ve been writing about Ruby lately has taken on a life of it’s own for me :), so I am going to quickly go over this topic if only for completeness sakes.

Raising Exceptions

Getting Ruby to raise an exception is easy :). Ruby, like many other languages has a hierarchy of exception classes (that all inherit from the class Exception), some of these are familiar and fairly easy to produce, for example ZeroDivisionError or NoMethodError. Here is some code which will do just that:

1/0

or

blah = Object.new
blah.hello

Of course you don’t have to wait for Ruby to raise exceptions for you, you can do so explicitly in your code with the raise keyword (it is actually a method). Lets write a method where we explicitly raise an exception if the argument we pass in is false:

def i_must_have_truth(value)
  raise TypeError, 'You must give me truth' if value == false
end
 
i_must_have_truth false

this prints:

D:\ruby-projects\scrap\lib\scrap.rb:15:in `i_must_have_truth': You must give me truth (TypeError)
        from D:\ruby-projects\scrap\lib\scrap.rb:18

As you can see we are able to raise a specific exception and pass it a message which then gets printed out to the console. There is also a handy shortcut, if you use raise without giving it a specific exceptions (or even without giving it an error message to display), Ruby will automatically raise a RuntimeException for you which is pretty handy:

def i_must_have_truth(value)
  raise "Hello"
end
 
i_must_have_truth false

this prints:

D:\ruby-projects\scrap\lib\scrap.rb:15:in `i_must_have_truth': Hello (RuntimeError)
        from D:\ruby-projects\scrap\lib\scrap.rb:18

Rescuing Exceptions

So far so good, but life would be pretty tough if we couldn’t handle the exceptions that get thrown in any way, This is where the rescue clause comes in. If we wrap some code in a begin .. end block and put a rescue clause in the middle of that, control will go to the rescue clause if any exception is thrown by the code. Let us demonstrate:

begin
  1/0
  p 'I should never get executed'
rescue
  p 'I am rescuing an exception and can do what I want!'
end

This produces the following output:

"I am rescuing an exception and can do what I want!"

As you can see the first string does not get printed since the division by zero will throw an exception and control will pass to the rescue clause, which will print out the second string for us.

Using rescue by itself will allow you to rescue all exceptions that get thrown by the code, but sometimes you might want to only capture specific ones and let other code handle all the others. The rescue clause allows you to do this as well:

i=0
while i<=10
  begin
    if i ==0
      1/0
    end
    raise "random runtime exception"
    p 'I should never get executed'
  rescue ZeroDivisionError
    p 'I am rescuing only ZeroDivisionErrors!'
    i+=1
  end
end

which gives us:

"I am rescuing only ZeroDivisionErrors!"
D:\ruby-projects\scrap\lib\scrap.rb:33: random runtime exception (RuntimeError)

As you can tell, we rescued the first exceptions since it was a division by zero, but the second exception does not get rescued and so the program exits with an error. However, we sometimes want to execute some code regardless of whether an exception was thrown or not (i.e. we may want to do some cleanup). Java has the finally keyword for this, Ruby has ensure. We can put an ensure clause within out begin .. end block. The code inside this clause gets executed regardless of whether the code throws an exception. For example, if we are reading from a file, we want to close the file handle no matter if an exception is thrown or not, we can do the following:

file = nil
begin
  file = File.open("blah.txt")
  raise
rescue
  p 'I rescue all exception and raise new ones'
ensure
  file.close
  p 'just closed the file'
end

as we expect the output is:

"I rescue all exception and raise new ones"
"just closed the file"

Even though an exception was thrown and rescued, the code in the ensure clause executes regardless.

Rescuing Exceptions Inside Methods

If we are inside a method and we want to rescue some exceptions, we don’t actually need a begin .. end block since the method definition itself will act in that capacity. So, we can do something like this:

def some_method
  p 'Hello method'
  raise
  p 'Bye method'
rescue
  p 'Rescuing exceptions'
end
some_method

which print out:

"Hello method"
"Rescuing exceptions"

We have rescued an exceptions without having a begin .. end block.

You are not limited to knowing just the type of the exception you’re rescuing, you can get more information at your disposal. When you rescue an exception you can get a hold of the actual exception object that was thrown and then query this object for various details. Here is how:

begin
  raise ZeroDivisionError, "Hello I am a random zero division error"
rescue ZeroDivisionError => e
  p e.message
  p e.backtrace
end

If we execute the above code we will print out the message as well as the stack trace of the exception we rescued which are provided by the exception object itself. You can also do the same thing with a general rescue clause:

begin
  raise "Hello I am a random runtime error"
rescue => e
  p e.message
  p e.backtrace
end

Finally if you have rescued an exception, but don’t want to handle it yourself (for whatever strange reason), calling raise within a rescue block with no parameters will allow you to re-raise the original exception that you have rescued rather than the normal behavior (i.e. raising a general runtime exception).

Creating Your Own Exceptions

Creating your own exceptions in Ruby is extremely simple, all you need to do is create a class that inherits from Exception or one of it’s descendants and you’re good to go:

class MyCrazyException < Exception
end
 
raise MyCrazyException, "I am a crazy new exception"

this prints out:

D:\ruby-projects\scrap\lib\scrap.rb:78: I am a crazy new exception (MyCrazyException)

As you can see Ruby is saying that it has raised our new exception rather than one of it’s regular ones. As usual, this allows you to define different types of exceptions for various error conditions in your code which also allows you to rescue them by name. You may or may not want to do this, you can easily get away with just using runtime exceptions but it is up to you.

Update: Several people have pointed out, in the comments that inheriting from Exception directly is a big no-no when creating custom exceptions. You should instead inherit from StandardError. This is because exceptions that inherit from StandardError deal with application level errors, while if you inherit Exception directly you risk catching errors to do with the environment. Also the convention is to end your exceptions with the word Error rather than exceptions e.g.:
class MyCrazyError < StandardError
end

The Ruby Exception Hierarchy

If you’re curious about the kinds of exceptions that Ruby has predefined for you, here is a list:

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal

You don’t have to take my word for it, you can derive it yourself :). The only thing that is missing from that list is the Errno family of exceptions. These are a whole set of exceptions that relate to file I/O and live in the Errno namespace. You can see one of these in action if you try to open a file that doesn’t exist, e.g.:

File.open("")

which gives you an Errno style exception:

D:\ruby-projects\scrap\lib\scrap.rb:80:in `open': No such file or directory - File not found -  (Errno::ENOENT)
        from D:\ruby-projects\scrap\lib\scrap.rb:80

That’s all, nothing too fancy, just the kinds of basics that everybody needs to know. You’re now a Ruby exception guru, go forth and use your new Ruby error handling powers for good instead of evil :).

Image by valentin.d

  • http://pixelwareinc.com Eric Anderson

    Nice article on exceptions.

    Wanted to make a note that people generally say you should inherit your own exception classes from StandardError rather than Exception. I think the only reason is that everything under StandardError has sometime to do with the current operation while stuff outside of StandardError deals more with the runtime environment. So code can “rescue StandardError” to catch everything that might go wrong caused by the code while still letting errors about the environment continue to rewind the call stack.

    Also when creating your own exceptions the convention is to end the class with “Error” not “Exception”. Although Ruby obviously violates this convention itself with the “Exception” and “SignalException” class. Also some classes don’t have any suffix like “Interrupt”, “SystemExit” and “fatal”.

    Also you mentioned that exceptions in Ruby are pretty much like other languages. But there are some nice features that I don’t often seen in other languages such as:

    * Multiple rescue blocks – Most languages support this but not all
    * The “else” block – Although personally I never use this as you can just put this code at the end of the “begin” block.
    * The “retry” keyword to run the entire block again. Most languages you have to put the entire block in a loop and have a flag to indicate when it should stop running.
    * Calling just “raise” to re-raise the current exception in the “rescue” block. Many languages you have to reconstruct the exception yourself.
    * Being able to capture multiple exception types in the same rescue block by just separating the types by a comma.

    Also on a somewhat related note Ruby has the “catch” and “throw” keywords to manage execution flow. This is not an exception at all but more like a cross between an exception and a “goto” statement.

    • http://www.skorks.com Alan Skorkin

      Cheers for all the great info, good to know about StandardError.

      I didn’t even know about the fact that you could use the retry keyword to run a begin block again, that is definitely handy.

      This is I think the real value in blogging, when people come along and add to and expand on what you’ve written, to increase your knowledge and help anyone else who reads it later.

  • Coffee_fan

    Nice write-up. Good also that you put the pattern that occurs in methods where begin/end are redundant.

    • http://www.skorks.com Alan Skorkin

      Thanks, yeah I find that one to be a nice shortcut. It’s these kinds of little shortcuts that really make me dig Ruby.

  • apeiros

    Hi there, it’s me again :)
    Thanks a lot for the good article. I think it will be helpful to many.
    One thing though:
    You should *not* inherit from Exception when creating your custom exception. Instead you should inherit from at least RuntimeError. When I say at least, this means the further down the inheritance you can go, the better. E.g. for errors you raise with invalid arguments, you may want to subclass ArgumentError.
    Why you shouldn’t subclass exception: rescue without an explicit exception class will default to StandardError. This for good reason: SystemExit, Interrupt (caused by ctrl-C) and some others that you shouldn’t want to rescue per default are not StandardErrors but inherit from Exception directly. So another often seen malpractice is to do: rescue Exception.

    regards
    Stefan Rusterholz, @apeiros

    • http://www.skorks.com Alan Skorkin

      So you’re saying that signals are treated as exceptions? So rescuing Exception can allow you to catch ctrl-C, that’s really interesting I have to play around with this :). I’ve been meaning to write something about unix signals anyway, this might be a good opportunity.

      Yeah, rescuing Exception is no good whatever language you’re using. Although I can see how this could be particularly bad with Ruby (with Java I sometimes do this just so I can re-throw it as a RuntimeException :)).

  • http://entp.com Jeremy

    Do *not* inherit new exceptions from Exception. This will cause a lot of bad things. Exceptions are meant for nuclear bugs (segfaults, etc.), not minor errors. Always inherit from StandardError unless you really need to kill the whole app when something happens.

    • http://www.skorks.com Alan Skorkin

      A couple of people have mentioned this one, thanks for the info, I appreciate it.

  • lostwarrior

    Hi i have seen your post in rubyflow, and i saw the comments.Don’t get worried about that, the materials you are posting in your blog may be available in agile book or in ruby pdf.But it will be usefull for the Ruby on rails beginners and you too.Try to do a little bit about ruby blocks and some crispy rails application in your blog.

    regards,
    Gen.lostwarrior

    • http://www.skorks.com Alan Skorkin

      Thanks man, yeah I saw the comment and replied. It doesn’t really bother me, people are entitled to their own opinion, if they don’t like what I write they’ll just go and read something else which is perfectly alright.

      I write what I am learning and what I am thinking about as well as about anything else I find interesting. Some of it you can find in books and online (possibly because I read books as well as the web :)), other stuff is my own opinions and ideas. I post it all to various places so that other people have a chance to read it too, but only if they want to :).

      I’ll keep blogging about ruby basics, and once I run out of basics, about more advanced stuff, after that we’ll see, because right now that is what I am finding interesting.

  • http://ra66i.org raggi

    You shouldn’t really use Exception as the base class for custom exceptions. rescue without arguments only rescues from StandardError.

    When creating your own exceptions, I strongly recommend storing the data that caused the exception on the exception object itself. This greatly aids in debugging, especially in a well tested environment.

    Example:

    class MyError < StandardError
    attr_accessor :some_object, :some_operation
    def initialize(object, operation)
    @some_object, @some_operation = object, operation
    super("Failed to perform #{operation} on #{object}")
    end
    end

    You can even use these error classes as domain events, and avoid raising them in a raise free architecture.

  • http://ra66i.org raggi

    Sorry for re-raising the same point on Exception catches, I guess it’s time you correct the article?

    • http://www.skorks.com Alan Skorkin

      No at all, I appreciate the prod :), I should have updated it straight away, but over the weekend time got away from me. Thanks for the reminder, I will update the post shortly (most likely sometime tomorrow).

  • Pingback: Getting to know ruby exceptions « Ruby Noobie

  • Vinay Shenoy

    Great article. I’m new to Ruby and Rails and I found your articles very helpful. I just have a query about Exception Handling.

    I’m using the OAuth gem to handle authenticating my server with Twitter
    @request_token = @consumer.get_request_token(:oauth_callback => @callback_url)

    It was working fine, but the Twitter server got overloaded for a few seconds and the code threw an exception on my server console
    Net::HTTPFatalError (503 “Service Unavailable”):app/controllers/accounts_controller.rb:64:in `connect’

    How can I handle this exception in my code? Anything I found seemed to deal with handling the exception in the same method it was raised.

  • Tomo

    Super article. I’ve referred to it many times.

    One confusing thing for me is that the begin…end ‘thing’ in ruby is *not* a block (in the ruby block terminology), it’s just a bunch of code.

    begin
    zz = “top”
    rescue Exception => e
    end
    puts zz

    The variable zz is available outside the ‘block’! If it were an each code block:

    (1..10).each do | i |
    zz = “top”
    end
    puts zz

    You will get an error because zz is undefined. Hence, begin…end does not create a block, it’s just an expression. I find it confusing when it is referred to as a block.

  • csam

    Great infor helped me alot. Thanks

  • JJ

    Super useful, thanks!

  • flakyfilibuster

    thanks Skorks!

  • http://twitter.com/walteryu walteryu

    Great, thanks for sharing!

  • Pingback: » Catching exceptions in Ruby SnowCrash

  • Pingback: Set a default error message in Ruby Exception

  • Pingback: 王筝的博客 » Rescuing Exceptions Inside Methods

  • mrk

    Hi,
    What happens to statements after raise statement ? Are those executed ?
    For e.g is stement2 executed in below method?
    def method
    statement1
    raise SomeException
    statement2
    end