Ruby Exception List

Understanding Ruby's built-in error types

⚠️ What are Ruby Exceptions?

Ruby exceptions are error objects that signal when something goes wrong in your program. Understanding different exception types helps you handle errors gracefully and write more robust, reliable code that doesn't crash unexpectedly.


# Handling exceptions
begin
  result = 10 / 0
rescue ZeroDivisionError => e
  puts "Error: #{e.message}"
end
                                    

Output:

Error: divided by 0

Exception Categories

🔢

Math Errors

Errors from mathematical operations

ZeroDivisionError
FloatDomainError
📛

Name Errors

Errors from undefined names

NameError
NoMethodError
📄

File Errors

Errors from file operations

IOError
EOFError
🔤

Type Errors

Errors from type mismatches

TypeError
ArgumentError

🔹 StandardError Exceptions

StandardError is the parent class for most common exceptions. These are the errors you'll typically rescue in your code. They represent recoverable errors that your program can handle gracefully without crashing.

# ArgumentError - wrong number of arguments
def greet(name)
  puts "Hello, #{name}"
end

begin
  greet()
rescue ArgumentError => e
  puts "ArgumentError: #{e.message}"
end

# TypeError - wrong type
begin
  result = "5" + 5
rescue TypeError => e
  puts "TypeError: #{e.message}"
end

# RuntimeError - generic error
begin
  raise "Something went wrong"
rescue RuntimeError => e
  puts "RuntimeError: #{e.message}"
end

Output:

ArgumentError: wrong number of arguments (given 0, expected 1)
TypeError: String can't be coerced into Integer
RuntimeError: Something went wrong

🔹 Math and Number Exceptions

Math exceptions occur during numerical operations. These errors happen when you perform invalid mathematical calculations like dividing by zero or taking the square root of negative numbers in certain contexts.

# ZeroDivisionError
begin
  result = 100 / 0
rescue ZeroDivisionError => e
  puts "ZeroDivisionError: #{e.message}"
end

# FloatDomainError
begin
  result = Math.sqrt(-1)
rescue FloatDomainError => e
  puts "FloatDomainError: #{e.message}"
end

# RangeError
begin
  ("a".."z").to_a[100]
rescue RangeError => e
  puts "RangeError: #{e.message}"
end

Output:

ZeroDivisionError: divided by 0
FloatDomainError: Numerical argument is out of domain
RangeError: (no error in this case, returns nil)

🔹 Name and Method Exceptions

Name exceptions occur when Ruby can't find a variable, constant, or method. These are common errors when you have typos or try to use something before defining it. They help catch spelling mistakes early.

# NameError - undefined variable or constant
begin
  puts undefined_variable
rescue NameError => e
  puts "NameError: #{e.message}"
end

# NoMethodError - method doesn't exist
begin
  result = "hello".non_existent_method
rescue NoMethodError => e
  puts "NoMethodError: #{e.message}"
end

# NoMethodError - nil object
begin
  value = nil
  result = value.upcase
rescue NoMethodError => e
  puts "NoMethodError on nil: #{e.message}"
end

Output:

NameError: undefined local variable or method `undefined_variable'
NoMethodError: undefined method `non_existent_method' for "hello":String
NoMethodError on nil: undefined method `upcase' for nil:NilClass

🔹 Index and Key Exceptions

Index exceptions happen when accessing array or hash elements incorrectly. While Ruby often returns nil for missing elements, you can raise exceptions explicitly to enforce stricter error handling in your applications.

# IndexError - array index out of bounds
begin
  arr = [1, 2, 3]
  arr.fetch(10)
rescue IndexError => e
  puts "IndexError: #{e.message}"
end

# KeyError - hash key doesn't exist
begin
  hash = { name: "Alice" }
  hash.fetch(:age)
rescue KeyError => e
  puts "KeyError: #{e.message}"
end

# StopIteration - no more elements
begin
  enum = [1, 2, 3].each
  4.times { puts enum.next }
rescue StopIteration => e
  puts "StopIteration: #{e.message}"
end

Output:

IndexError: index 10 outside of array bounds
KeyError: key not found: :age
1
2
3
StopIteration: iteration reached an end

🔹 File and IO Exceptions

IO exceptions occur during file operations and input/output tasks. These errors happen when files don't exist, permissions are denied, or you reach the end of a file. Proper handling prevents data loss.

# IOError - general IO error
begin
  file = File.open("nonexistent.txt")
rescue Errno::ENOENT => e
  puts "File not found: #{e.message}"
end

# EOFError - end of file reached
begin
  File.open("test.txt", "w") { |f| f.write("test") }
  File.open("test.txt", "r") do |f|
    f.read
    raise EOFError, "Reached end of file"
  end
rescue EOFError => e
  puts "EOFError: #{e.message}"
end

# SystemCallError - system-level error
begin
  Dir.mkdir("/root/forbidden")
rescue SystemCallError => e
  puts "SystemCallError: #{e.message}"
end

Output:

File not found: No such file or directory @ rb_sysopen
EOFError: Reached end of file
SystemCallError: Permission denied

🔹 Custom Exception Handling

You can create custom exceptions for specific error scenarios in your application. Custom exceptions make your code more maintainable by providing clear, meaningful error messages that describe exactly what went wrong.

# Creating custom exceptions
class InvalidAgeError < StandardError
  def initialize(age)
    super("Invalid age: #{age}. Age must be between 0 and 120.")
  end
end

class InsufficientFundsError < StandardError; end

# Using custom exceptions
def validate_age(age)
  raise InvalidAgeError.new(age) if age < 0 || age > 120
  puts "Valid age: #{age}"
end

def withdraw(amount, balance)
  raise InsufficientFundsError, "Not enough funds" if amount > balance
  balance - amount
end

begin
  validate_age(150)
rescue InvalidAgeError => e
  puts e.message
end

begin
  withdraw(100, 50)
rescue InsufficientFundsError => e
  puts "Error: #{e.message}"
end

Output:

Invalid age: 150. Age must be between 0 and 120.
Error: Not enough funds

🧠 Test Your Knowledge

Which exception is raised when dividing by zero?