How to Read and Resolve Common Error Codes in Ruby

Gabbie Piraino
10 min readJan 3, 2019

--

“There are two ways to write error-free programs; only the third one works.”

— Alan J. Perlis

As someone who recently entered the programming world, one of my first hurdles was a purely mental obstacle: errors and failing aren’t a bad thing. Though ingrained otherwise (hello, 18+ collective years of academia), it was important for me to understand that you’ll fail more often than you succeed when you’re coding. Imagine how frustrated you’d be without reversing your attitude!

As I quickly learned, errors will give you a hint on how to self-correct and write successful code — but only if you can read them correctly! Even as an advanced programmer, you’ll still need to debug your own code (not including code from your colleagues or other developers), so understanding how to read and resolve the error is an integral skill at every experience level.

In this blog, we’ll first break down the error response itself so you know how to interpret the information, and then review the most common error types that may arise while you’re coding. Once you have a solid understanding of these concepts, you’ll be more successful in reworking your code and might find yourself leaping over pitfalls before you make the errors themselves.

**As a quick note, this article will be focused on how errors report and error types in Ruby, as this is the primary language that I’m currently learning in Flatiron School.

Photo by Ian Kim on Unsplash

Stack Trace

Before we jump into reading error messages, first let’s discuss at a very basic level what’s going on behind the scenes every time you run your code. Understanding how errors themselves are raised will be helpful towards actually interpreting the error and completing the requisite detective work to resolve it in your code.

Your computer comes with a compiler: a program that translates your code from whatever programming language you’re currently using into machine code — or instructions that your computer can effectively understand. Every time you run your program, the compiler sends the translated instructions, line by line, with a specific MO to complete the instructions, to the computer… that then returns the completed task (or series of tasks, depending on the complexity of your program) to the user.

A “call stack” (sometimes referenced to as an “execution stack,” “program stack,” “control stack,” “run-time stack,” or “machine stack”), but most often just called the “stack”, is a data structure that stores information about the program itself and the order of its operations. In layman’s terms, it’s how and when the computer completes each step of your instructions. A stack is made up of “stack frames”: smaller structures that correspond with an individual call to a method — including the method’s arguments and variables — that hasn’t yet completed its return. Each stack frame builds upon the frame before it.

introduction.rb1 def introduction #<=(step 2, reference the method definition)
2 puts “hello, world!” #<=(Step 3, calls #puts method; Step 4, prints string to your console)
3 end
4
5 introduction #<=(step 1, call the #introduction method)
"hello, world!"
=> nil

In the above introduction method, the stack will evaluate each step in the following order:

Step 1. The method “introduction” is called in line 5. (It skips over the definition of “introduction” until it is asked to actually utilize the method)

Step 2. It then references the “introduction” method that is defined above in lines 1–3

Step 3. It calls another method, “puts” within “introduction,” and it has to add this to the stack — it cannot execute “introduction” without first executing “puts”

Step 4. It collects string “hello, world!” and prints it to the console

The stack trace (also “backtrack,” “stack backtrace,” or “stack traceback”) is the readable version of the stack as it performs the evaluations and runs your program. The stack trace for the above program would look as follows:

introduction.rb:1 in ‘puts’
introduction.rb:1 in ‘introduction’
introduction.rb:5 in ‘<main>’

Let’s dissect it. First, it references the location — we’re in the hypothetical file introduction.rb. If you read from bottom to top: in the <main> scope of your file, on line 5, we called the introduction method, which began on line 1, which required us to also call the puts method. Because the puts method is called within the introduction method, both report line 1.

In the event of an error, the error message will include the stack trace to help you pinpoint the origin, and most helpfully, the location of the error. With more complicated methods, especially those that may reference multiple methods you have defined elsewhere, your stack trace can get quite long and you will have to walk backwards through your code in order to determine the line in which your code wasn’t written correctly.

Reading Error Messages

Photo by Jason Leung on Unsplash

Every Ruby error message is comprised of three important elements: a type, a location, and a description.

introduction.rb1 def introduction
2 puts “hello, world!”
3 end
4
5 intro
NameError: undefined local variable or method `intro’ for main:Object
Did you mean? introduction
from introduction.rb:5
in `<main>’

In the above error response, the type of error is a NameError.

The location is introduction.rb: 5in <main>. To break that down further, the error is pointing to a file location — in this case, our introduction.rb — and specifically notes that the error took place in line 5, in the <main> scope.

The description is undefined local variable or method ‘intro’.

Oftentimes, the error will also suggest a solution — in this case, Did you mean? introduction. The compiler recognizes that you have a method defined with a similar name to intro and is offering that perhaps you intended to call the introduction method instead. In this case, it is perfectly correct. We need to call introduction instead of intro since we have not defined any method named intro. Once we make this adjustment to line 5, the console would then print:

1 def introduction
2 puts “hello, world!”
3 end
4
5 introduction
“hello, world!”
=> nil

Great! We now successfully read the error message for hints, identified the specific error in our code, and applied a solution so that our code can run successfully!

Common Error Types

“When debugging, novices insert corrective code; experts remove defective code.”

— Richard Pattis

If we take Richard Pattis’ advice, the goal of reading error codes should always be to revise our original code in order to create effective code that completes our intended task(s). The following types of errors are those that I’ve found to be most common through my research and my own coding experiences.

Name Errors

A NameError arises when an object in your code is undefined or invalid. In my experience, these exceptions arise when I’m not focused, or I’m writing my code too quickly. Let’s look at an example; here we want to print nemo to the console.

# rubyerrors.rb1 puts nemo
NameError: undefined local variable or method `nemo’ for main:Object
from rubyerrors.rb:1:in `<main>’

In the above, the NameError points to string as the undefined variable or method. Since Ruby is an object-oriented programming language, it typically assumes that every element is an object, and therefore needs to be defined. In order to puts a string, the correct syntax here is “string”.

In order to resolve this error, we can refactor our code as best suits the context.

# rubyerrors.rb1 puts “nemo”=> “nemo”

NoMethod Errors

A subclass of the NameError is the NoMethodError. A NoMethodError is raised when an undefined method is called on an object. Perhaps you haven’t yet written that method — oops! — or you didn’t call the correct method name (as we saw above in the example above section, Reading Error Messages). In this example, let’s print a random boast about Gaston.

# rubyerrors.rb
...
3 boast_gaston
NoMethodError: undefined method `boast_gaston’ for main:Object
from rubyerrors.rb:3:in `<main>’

Here we can see that we’re calling a method named boast that hasn’t yet been defined. In order to fix this, we have to add that method to our code and then call the method. Let’s revise our code to reflect this:

# rubyerrors.rb
...
3 def boast_gaston
4 boasts = [“No one\’s slick as Gaston”, “No one\’s quick as Gaston”, “No one\’s neck\’s as incredibly thick as Gaston”, “No one\’s got a swell cleft in his chin like Gaston”, “No one fights like Gaston”, “In a wrestling match nobody bites like Gaston”, “No one shoots like Gaston”, “In a spitting match nobody spits like Gaston”]
5 puts boasts.sample(1)
6 end

7
8 boast_gaston
No one’s got a swell cleft in his chin like Gaston
=> nil

Here, you can see that we wrote a method that uses the .sample method to select (1) element from the options array and then puts it to the console. It returns nil because we haven’t asked the method to actually return anything. (NB: You can also call puts boast.sample without (1) to only return one random element from your array. However, if you wanted to call two random elements, you would have to call puts boast.sample(2))

If we wanted that instead, we could revise again:

# rubyerrors.rb
...
3 def boast_gaston
4 boasts = [“No one\’s slick as Gaston”, “No one\’s quick as Gaston”, “No one\’s neck\’s as incredibly thick as Gaston”, “No one\’s got a swell cleft in his chin like Gaston”, “No one fights like Gaston”, “In a wrestling match nobody bites like Gaston”, “No one shoots like Gaston”, “In a spitting match nobody spits like Gaston”]
5 return boasts.sample(1)
6 end
7
8 boast_gaston
=> [“In a spitting match nobody spits like Gaston”]

Syntax Errors

A SyntaxError is when your syntax doesn’t match the rules of your specific programming language. My most common Ruby syntax error is when I misplace an end in my code. Let’s create a schedule for Jasmine’s royal tour on behalf of Agrabah.

# rubyerrors.rb
...
10 def royaltour(princess)
11 puts “#{princess} is going to:\n”
12 locations = [“Beirut”, “Abu Dhabi”, “Cairo”, “Riyadh”, “Baghdad”, “Tehran”, “Alexandria”]
13 locations.each_with_index {|city, index| puts “#{index+1}. #{city}”
14 end
15
16 royaltour(“Jasmine”)
SyntaxError: unexpected keyword_end, expecting ‘}’ for main:Object
from rubyerrors.rb:14:in `<main>’

If we parse the error message, we can see that the type of error is a SyntaxError: something in our code doesn’t conform to what Ruby expects. The location of the error is in line 14. The message denotes that the end in line 14 is unexpected, but it was anticipating a closing curly bracket (you may also hear this called a ‘brace’). The error here is hinting that we’re missing a } before we arrive at the end in the fourteenth line. So if we were to revise our code in order to resolve this error, it would look as follows:

# rubyerrors.rb
...
10 def royaltour(princess)
11 puts “#{princess} is going to:\n”
12 locations = [“Beirut”, “Abu Dhabi”, “Cairo”, “Riyadh”, “Baghdad”, “Tehran”, “Alexandria”]
13 locations.each_with_index {|city, index| puts “#{index+1}. #{city}”}
14 end
15
16 royaltour(“Jasmine”)
Jasmine is going to:
1. Beirut
2. Abu Dhabi
3. Cairo
4. Riyadh
5. Baghdad
6. Tehran
7. Alexandria
=> [“Beirut”, “Abu Dhabi”, “Cairo”, “Riyadh”, “Baghdad”, “Tehran”, “Alexandria”]

Type Errors

A TypeError occurs when the object is not the expected datatype for your method. A common instance of this is when you try to do a mathematical equation on a string. In our example, let’s use the Seven Dwarfs and ask which ones are currently in the mine.

# rubyerrors.rb
...
18 dwarfs = [“Doc”, “Grumpy”, “Happy”, “Sleepy”, “Bashful”, “Sneezy”, “Dopey”]
19
20 dwarfs.sample(“4”)
TypeError: no implicit conversion of String into Integer
from rubyerrors.rb:20:in `sample’

Here we can see that we tried to call a method, .sample, that requires an argument of a Fixnum (i.e. integer) but passed in a string. Because the type of the argument didn’t match what was required, the TypeError exception was raised. In order to revise this, we need to simply change our string into a fixnum:

# rubyerrors.rb
...
18 dwarfs = [“Doc”, “Grumpy”, “Happy”, “Sleepy”, “Bashful”, “Sneezy”, “Dopey”]
19
20 dwarfs.sample(4)
=> [“Sneezy”, “Dopey”, “Sleepy”, “Happy”]

Argument Errors

An ArgumentError is fairly self evident — the code requires a different number of arguments than you passed in, either fewer or more. However, another way to raise this exception is by passing in an argument that isn’t a valid parameter, which would raise the same exception. In this last example, let’s ask Mulan if one of her friends is a sidekick.

# rubyerrors.rb
...
22 def mulan
23 if [“Mushu”, “Cri-Kee”].include? name
24 puts “Yes, #{name} is my sidekick.”
25 else
26 puts “No, #{name} is not my sidekick.”
27 end
28 end
29
30 mulan(“Ling”)
ArgumentError: wrong number of arguments (given 1, expected 0)
from rubyerrors.rb:22:in `mulan’
from rubyerrors.rb:30:in `<main>’

In this ArgumentError, we can see that the error arose in line 30 when we called mulan(“Ling”). Line 30 references above to line 22 of the mulan method, which is included in the stack trace. We gave the mulan method an argument of (“Ling”) in line 30 but the method mulan didn’t expect any!

In the original definition of the mulan method, we didn’t allow the method to pass in an argument — which is represented by (“Ling”) in line 30. We can see, however, that a mysterious object, name, appears quite a few times throughout the method… and Ling is a name. So we should be led to the realization that we need to give the mulan an argument that should be called name so that the method can determine if the friend (identified by their name) is qualified as her sidekick. Mulan’s only sidekicks here are Mushu and Cri-Kee. In order to revise the code to run correctly, we need to allow for the argument in line 22.

# rubyerrors.rb
...
22 def mulan(name)
23 if [“Mushu”, “Cri-Kee”].include? name
24 puts “Yes, #{name} is my sidekick”
25 else
26 puts “No, #{name} is not my sidekick”
27 end
28 end
29
30 mulan(“Ling”)
No, Ling is not my sidekick
=> nil
Photo by Trent Erwin on Unsplash

Now that we’ve walked through how to read error messages and the most common Ruby error types, you should be able to parse out hints from error messages that are raised for your code in the future. My best advice is when you’re stumped, to read the entire error message twice …and then use your trusty friend, Google. StackOverflow is one of my favorite go-to sources for help, as well as the Ruby-Doc pages.

Good luck out there, and happy coding!

Sources

Ruby-Doc: Exception

Ruby-Doc: NameError

Ruby-Doc: NoMethodError

Ruby-Doc: SyntaxError

Ruby-Doc: TypeError

Ruby-Doc: ArgumentError

Wikipedia: Call Stack

AppSignal: Reading and Understanding Stack Traces

ExceptionalCreatures: NoMethodError

--

--

Gabbie Piraino

Current Tech Geek | Previous Book Nerd | Always Doggo Lifestyle