How to raise any object as a Ruby exception

It's a common misconception that the raise method only accepts exceptions as its argument. This post will show you how you can raise ANYTHING, including numbers, dates, and your own custom classes.

Ruby's raise syntax gives you a couple of options for specifying the kind of error you want raised. In the code below, I've shown three ways to raise a RuntimeError.

raise "hello"
raise RuntimeError, "hello"
raise RuntimeError.new("hello")

# ...all of the above result in "RuntimeError: hello"

That's nice, but what happens when I want to raise something other than an exception? What if I wanted to raise a number? Well, Ruby won't let me. I'd get an error message like this:

raise 1
# TypeError: exception class/object expected

Now this message might lead you to believe that raise expects an exception class/object as a parameter. But that's incorrect!

Introducing the exception method

If you do raise foo the raise method doesn't expect foo to be an exception object. It expects that it will get an exception object whenever it calls foo.exception.

The thing to remember is that you can pass ANYTHING to raise, just as long as it has a method called exception that returns an exception.

So, if you wanted to, you could monkeypatch ruby's number classes to allow you to raise a number. Here's what that might look like:

class Fixnum
  def exception
    RuntimeError.new("I'm number: #{ self }")
  end
end

raise 42
# ...results in raise_number.rb:7:in `<main>': I'm number: 42 (RuntimeError)

This is a neat party trick, but could it ever be useful in real life? The main practical application I see for this technique is to separate the logic required to build an exception from the logic that decides to raise the exception. This is certainly a bit of an edge case. But let's see what that might look like.

A possibly practical example

Suppose I want to read a line of data from some kind of IO. It could be network IO, it could be a file. It doesn't really matter. I just want to read the data and see if it's valid.

If the data I read isn't valid, I want to raise an exception. But the exception needs to be tailored to the input. A network connection needs to have different debug info than a local file. I can do that by providing custom exception methods for each kind of input class. Here's some pseudo-ruby showing what that might look like.

# These three classes represent different kinds of IO with different exceptions.
class NetworkConnection
  ...
  def exception
    NetworkConnectionError.new(url: url, ...)
  end
end

class LocalFile
  ...
  def exception
    FileError.new(path: path, ...)
  end
end

class UnixPipe
  ...
  def exception
    PipeError.new(...)
  end
end

def read_all(*items)
  items.each do |item|
    if item.readline != "foo"
      # We raise the item, which causes the appropriate exception class to be used. 
      raise item
    end
  end
end

read_all(NetworkConnection.new(url: "example.com"), LocalFile.new("/something"), UnixPipe.new)

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Starr Horne

    Starr Horne is a Rubyist and Chief JavaScripter at Honeybadger.io. When she's not neck-deep in other people's bugs, she enjoys making furniture with traditional hand-tools, reading history and brewing beer in her garage in Seattle.

    More articles by Starr Horne
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like: