← Learning center

Understanding Ruby error messages and backtraces

Understanding Ruby error messages and backtraces

It's important to understand what your application's error type is telling you when debugging an issue.

In this article, we'll show you how to read an error message, backtrace, and walk you through some examples of common Ruby error types, what you may encounter in your Ruby application, and how to tackle them.

How to read an error message

Error messages are most often output in the following format:

ruby
file_location:line_number: error description (ErrorCode)

For example, considering the following example:

ruby
articles_controller.rb:27: wrong number of arguments (given 3, expected 2) (ArgumentError)

We can deduce the following:

  1. Error location: Line 27 of the articles_controller.rb file
  2. Error type: ArgumentError
  3. Error Message: wrong number of arguments (given 3, expected 2)

Which can be understood as: "On line 27, in the articles_controller.rb file, three arguments were passed to a method, but the method expected two arguments"

How to read a backtrace

Whenever an error occurs in your application, Ruby will raise an exception and log a backtrace (also known as a stack trace), which you can then use to find the location of an error within your application's code.

In Ruby, if you try and divide a number by zero, you will raise a ZeroDivisionError. To demonstrate a backtrace, let's raise one:

ruby
# maths_is_hard.rb def divide(a, b) "#{a} divided by #{b} equals #{a / b}." end puts divide(6, 0)

In the above code snippet, we've created a method called divide(a, b), which will divide any two integers we provide it. Let's run the code in our terminal to raise ZeroDivisionError and print a backtrace:

ruby
$ ruby maths_is_hard.rb maths_is_hard.rb:2:in `/': divided by 0 (ZeroDivisionError) from maths_is_hard.rb:2:in `divide' from maths_is_hard.rb:5:in `<main>'

So, what is our backtrace telling us? Let's look at it line per line:

  1. The first line tells us: On line 2 of maths_is_hard.rb a ZeroDivisionError via a method named / (our division operator).
  2. The second line tells us: the divide method was called on line 2 of the maths_is_hard.rb file.
  3. The third line tells us: that our method was called from Line 5 of maths_is_hard.rb, in <main>, which is the initial context of our Ruby application, essentially meaning we didn't call it from a method, which we didn't, we executed the code directly from our terminal.

We can use this backtrace to deduce where the error was raised in our code and where the method was called from. In the case of the example above, we know the issue was caused by 0 being passed as an argument on maths_is_hard.rb:5. We could then make sure not to pass 0 as an argument or modify our method to safely return a message if 0 is passed as an integer:

ruby
def divide(a, b) if b.zero? puts '0 is not a valid division argument' else "Dividing #{a} by #{b} gives #{a / b}." end end puts divide(6, 0)

Which would output the following when run:

ruby
$ ruby main.rb 0 is not a valid division argument

Good to know: We're using shorter backtraces here for brevity, but your application's backtrace will often be much longer. However, the same logic to reading backtraces applies, regardless of length.

Common error types

There are many types of errors in Ruby. In this article, we'll cover four common Ruby error types. To learn more about Ruby error types, you can read the Ruby Exception class documentation.

ArgumentError

ArgumentError is raised when you call a method with the wrong number of arguments or with the wrong names for keyword arguments.

Positional arguments

In the below example, we are calling the publish method, which uses positional arguments. With positional arguments, it's important to provide information in the expected order when invoking a method.

ruby
# article.rb def publish(published_at, published_by) update( published: true, published_at: published_at, published_by: published_by ) end

If we forget to provide a required argument, an ArgumentError will be raised, informing us that we've provided too few arguments:

ruby
irb(main):001:0> article.publish(DateTime.now) (irb):1:in `publish': wrong number of arguments (given 1, expected 2) (ArgumentError)

We'll also raise an ArgumentError if we provide too many arguments:

ruby
irb(main):002:0> article.publish(DateTime.now, User.find(12), Article.find(122)) (irb):48:in `publish': wrong number of arguments (given 3, expected 2) (ArgumentError)

Keyword arguments

In the below example, we are calling the publish method, which uses keyword arguments. Keyword arguments are defined with a keyword. This is a useful way to ensure the correct information is passed to methods with several arguments.

The position of keyword arguments when invoking a method does not matter.

ruby
# article.rb def publish(published_at:, published_by:) update( published: true, published_at: published_at, published_by: published_by ) end

If we forget to provide a required argument, an ArgumentError will be raised informing us which keyword argument is missing:

ruby
irb(main):001:0> article.publish(published_at: Time.now) (irb):1:in `publish': missing keyword: :published_by (ArgumentError)

We'll also raise an ArgumentError if we provide an unknown keyword argument, for example, "publisher":

ruby
irb(main):001:0> article.publish(published_at: Time.now, published_by: User.find(12), publisher: 'AppSignal') (irb):1:in `publish': unknown keyword: :publisher (ArgumentError)

Error Position

When the error is raised when a method is invoked in a Ruby process, you will also be told where the error occurred. For example, based on the error message below, we know we need to inspect line 12 of publisher.rb:

ruby
$ ruby publisher.rb publisher.rb:1:in `publish': wrong number of arguments (given 1, expected 2) (ArgumentError) from publisher.rb:12:in `<main>'

Resolution

To resolve ArgumentError errors, check what arguments the method you are calling is expecting and ensure you pass those arguments when calling the method in your code.

Let's use this logic to call publish on our article successfully:

ruby
# Let's assign our arguments to variables irb(main):001:0> user = User.find(6) => #<User:0x0000000005378a20 irb(main):003:0> published_at = DateTime.now => Wed, 28 Jun 2023 07:47:23 +0000 # when using positional arguments: article.publish(published_at, user) # or when using keyword arguments: irb(main):004:0> article.publish(published_at: published_at, published_by: user) => true

NameError

A NameError is raised when calling an attribute or method that is not defined.

For example, we want to assign the title of an article to the attribute title only we make a typo and accidentally assign it to an attribute incorrectly named titel, meaning when we call title in our code, we raise a NameError, because title is not defined.

ruby
irb(main):001:0> titel = @article.title irb(main):002:0> title (irb):2:in `<main>': undefined local variable or method `title' for main:Object (NameError)

Resolution

To resolve this error, we need to make sure we are calling attributes and methods that are correctly defined:

ruby
irb(main):003:0> title = "Ruby is the way!" irb(main):004:0> title => "Ruby is the way!"

NoMethodError

NoMethodError is raised when you call a method on an object that is not defined. In the example below, we call the publish_article method on the Article object; however, no publish_article method is defined on the Article class.

ruby
# articles_controller.rb def publish @article.publish_article end

This will result in the following error:

ruby
articles_controller.rb:27 in `<main>': `method_missing': undefined method `publish_article' for Article:Class (NoMethodError)

Resolution

To resolve the error, a defined method must be called on the object. We can do this by checking what methods are in the Article class or by calling the methods function to return an array of available methods for an Article object:

ruby
irb(main):001:0> article.methods => [:publish, :update, :destroy ] irb(main):002:0> article.publish => true

In this case, we found the publish method was available and used that instead. We can now update the publish method in our ArticlesController:

ruby
# articles_controller.rb def publish @article.publish end

TypeError

A TypeError occurs when an object is the wrong type for the action you are attempting to execute. For example, when trying to add an integer to a string:

ruby
irb(main):001:0> "1" + 2 (irb):1:in `+': no implicit conversion of Integer into String (TypeError)

Resolution

As 1 is a string, it has no numerical value and can't be added to another integer. To be added successfully, it must first be converted into an integer, and we can do this using Ruby's to_i function.

ruby
irb(main):001:0> "1".to_i + 2 => 3

Note that we can only convert textual representations of integers to integer objects, not strings:

ruby
irb(main):001:0> "one".to_i => 0 irb(main):002:0> "1".to_i => 1

Never miss an exception with AppSignal

With AppSignal Error Reporting, AppSignal can record and notify you when errors occur, helping you quickly resolve problems in your application's codebase.

Graph showing Ruby error in AppSignal

AppSignal's Error Reporting is just one of our many developer-driven features that help you get the most out of monitoring your application. Developers also enjoy using our monitoring because we offer:

  • An intuitive interface that is easy to navigate.
  • Simple and predictable pricing.
  • Developer-to-developer support.

If you're ready to monitor your application's errors, start a free trial with AppSignal today!

Start your free trial

Don’t let the bad bugs bite. Try AppSignal for free.

AppSignal offers a 30-day free trial, no credit card is required. All features are available in all plans. Start monitoring your application in just a few clicks!