How Can I Fix the Ruby Error When Building Largest Prime Factor?

Recently, I dove into some pure Ruby just for fun to challenge myself and understand the language at a deeper level. I wasn’t solving any real-world problem; I was simply curious about how I might calculate the largest prime factor of a number without relying on any built-in gems like Prime. This hands-on approach turned out to be really insightful, especially because I hit a frustrating yet enlightening error:
nil can't be coerced into Integer

This blog walks through that experience where I went wrong, what I learned, how I fixed it, and how I built in even more functionality to make the code cleaner and more educational.

My Code

LargestPrimeFactor
attr_accessor :factors_list, :prime_factors, :idx, :below_n, :half_num

def initialize(below_n)
@below_n = below_n
@half_num = (below_n / 2).floor
@idx = 2
@factors_list = []
@prime_factors = []
end

def prime_checker
sorted_list = factors_list.sort
sorted_list.combination(2) do |el, others|
if !prime_factors.include?(el) && others % el == 0
prime_factors << el
end
end
puts "Prime checker returned: #{prime_factors}"
end

def factors
congruent = (below_n % idx == 0)
not_listed = !factors_list.include?(idx)
number_candidate = idx

if congruent && not_listed && number_candidate
factors_list << number_candidate
puts "#{idx}"
puts "#{below_n}"
puts "why nil? #{below_n.divmod(idx)[0]}"
tmp = below_n.divmod(idx)[0]
self.idx = tmp # 👈 This was supposed to update the loop
puts "idx now: #{idx}"
elsif factors_list.length > 0 && (factors_list[-1] - idx < 0)
primes = prime_checker
puts "Prime factors: #{primes}"
puts "COMPLETE"
else
self.idx += 1
end
end

def find_primes
(1..half_num).each do |_|
factors
end
end
end

p = LargestPrimeFactor.new(10)
p.find_primes

The Error: nil can't be coerced into Integer

When I ran this code, here’s what happened:

10
why nil? 5
idx now: 5
Traceback (most recent call last):
...
largest_prime_factor.rb:46:in `-': nil can't be coerced into Integer (TypeError)

Explanation of the Problem

The error pointed to this line:

factors_list.length > 0 && (factors_list[-1] - idx < 0)

It was clear from the message: idx was nil at the time of subtraction.

But how did idx, which started as 2, end up as nil?

The issue was this line:

tmp = below_n.divmod(idx)[0]
idx = tmp

What I mistakenly did was assign tmp to a new local variable called idx, which only existed within the scope of the factors method. I never updated the actual instance variable @idx, so it eventually became stale, and the logic that relied on it failed.

The Fix

All I needed to do was explicitly refer to the instance variable using self:

self.idx = tmp

This ensures Ruby knows I’m setting the instance attribute, not just declaring a local variable that dies once the method ends.

Update Code with Practice Improvement

I didn’t stop at just fixing the bug. I also made a few enhancements:

  • Added a reliable is_prime? method
  • Removed fragile sorting logic from prime_checker
  • Introduced a method to return the largest prime factor cleanly
class LargestPrimeFactor
attr_accessor :factors_list, :prime_factors, :idx, :below_n, :half_num

def initialize(below_n)
@below_n = below_n
@half_num = (below_n / 2).floor
@idx = 2
@factors_list = []
@prime_factors = []
end

def is_prime?(num)
return false if num <= 1
(2..Math.sqrt(num)).each do |i|
return false if num % i == 0
end
true
end

def factors
if below_n % idx == 0 && !factors_list.include?(idx)
factors_list << idx
self.prime_factors << idx if is_prime?(idx)
end
self.idx += 1
end

def find_primes
while idx <= half_num
factors
end
end

def largest_prime
find_primes
prime_factors.max
end
end

# 🔁 Usage
p = LargestPrimeFactor.new(10)
p.find_primes
puts "Factors of 10: #{p.factors_list}"
puts "Prime Factors: #{p.prime_factors}"
puts "Largest Prime Factor: #{p.largest_prime}"

Run Compile

Factors of 10: [2, 5]
Prime Factors: [2, 5]
Largest Prime Factor: 5

Practice Feature You Can Add

FeatureDescription
all_factorsReturn all integer factors (not just primes)
is_prime? reuseYou can extract this method and reuse it across projects
largest_prime methodEasy access to the result with minimal effort
Error-proofing patternsAvoid variable shadowing with self. when necessary

Final Thoughts

This little journey reminded me of something crucial when coding in Ruby: variable scope matters more than you think. It’s very easy to assume you’re updating a value, when you’re actually creating a temporary variable that disappears after a method call.

For anyone learning Ruby, especially without frameworks like Rails to abstract things away, I’d highly recommend small exercises like this. They sharpen your mental model of how Ruby works under the hood and every bug, like this nil coercion issue, becomes a learning opportunity.

Related blog posts