Ruby Exception Handling

Ruby Exception Handling: KeyError

Next up in our deep dive through the Ruby Exception Handling series we’ll be dog-paddling our way around the KeyError. The KeyError is a descendant of the IndexError. Unlike the IndexError, which deals with Arrays, the KeyError deals with Hashes instead. Specifically, a KeyError occurs when a reference to a key within a hash is invalid or missing.

Throughout today’s article we’ll examine exactly what the KeyError means, see where it fits within the Ruby Exception class hierarchy, and analyze how to handle KeyErrors when they’re raised, so let’s get to it!

The Technical Rundown

  • All Ruby exceptions are descendants of the Exception class, or a subclass therein.
  • StandardError is a direct descendant of the Exception class, and is also a superclass with many descendants of its own.
  • IndexError is a direct descendant of the StandardError class, and is a superclass to a few descendants of its own.
  • KeyError is a direct descendant of the IndexError.

When Should You Use It?

Unlike the IndexError that is associated with improper use of Arrays, the KeyError is associated with improper use of Hashes. A Ruby Hash is effectively a dictionary object that contains a series of key/value pairs. This data structure is also commonly referred to as an associative array.

Just as with Arrays, a Hash can be created in a number of ways:

Also like Arrays, there are many methods that can be used to manipulate our Hash once initialized. We can use similar syntax to that of assignment to also retrieve values:

As with the Array.fetch method, we can also call the Hash.fetch method to retrieve a value from our Hash by passing the key value as the first argument, as seen above. However, if we pass an invalid key to Hash.fetch, let’s see what happens:

As expected, we raised a KeyError, since :published was not specified as a key in our Hash:

As a workaround, we can pass a second argument to Hash.fetch, which specifies a default value to return if the Hash doesn’t contain a matching key for the value we provided:

Now, rather than raising a KeyError, our call to Hash.fetch notices a default value of Time.now.to_s, and returns that as our output instead:

Finally, just as with Array.fetch, we can also initialize our call to Hash.fetch with an associated block, which forces Ruby to execute the block code if, and only if, the passed key value is invalid:

Now, instead of raising a KeyError, our output shows we gracefully failed out of that Hash.fetch method call:

To get the most out of your own applications and to fully manage any and all Ruby Exceptions, check out the Airbrake Ruby exception handling tool, offering real-time alerts and instantaneous insight into what went wrong with your Ruby code, including integrated support for a variety of popular Ruby gems and frameworks.