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.
Error messages are most often output in the following format:
file_location:line_number: error description (ErrorCode)
For example, considering the following example:
articles_controller.rb:27: wrong number of arguments (given 3, expected 2) (ArgumentError)
We can deduce the following:
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"
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:
# 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 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:
/
(our division operator).maths_is_hard.rb
file.<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:
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 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.
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
is raised when you call a method with the wrong number of arguments or with the wrong names for keyword 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.
# 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:
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:
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)
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.
# 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:
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":
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)
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 publisher.rb publisher.rb:1:in `publish': wrong number of arguments (given 1, expected 2) (ArgumentError) from publisher.rb:12:in `<main>'
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:
# 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
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.
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)
To resolve this error, we need to make sure we are calling attributes and methods that are correctly defined:
irb(main):003:0> title = "Ruby is the way!" irb(main):004:0> title => "Ruby is the way!"
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.
# articles_controller.rb def publish @article.publish_article end
This will result in the following error:
articles_controller.rb:27 in `<main>': `method_missing': undefined method `publish_article' for Article:Class (NoMethodError)
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:
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
:
# articles_controller.rb def publish @article.publish end
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:
irb(main):001:0> "1" + 2 (irb):1:in `+': no implicit conversion of Integer into String (TypeError)
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.
irb(main):001:0> "1".to_i + 2 => 3
Note that we can only convert textual representations of integers to integer objects, not strings:
irb(main):001:0> "one".to_i => 0 irb(main):002:0> "1".to_i => 1
With AppSignal Error Reporting, AppSignal can record and notify you when errors occur, helping you quickly resolve problems in your application's codebase.
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:
If you're ready to monitor your application's errors, start a free trial with AppSignal today!
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!