RbRuby · Lesson 9 of 11

Error Handling

Ruby calls exceptions exceptions. `begin/rescue/ensure` is Ruby's try/catch/finally. `raise` throws them. Custom exception classes are just subclasses of StandardError.

Ruby
# Basic rescue
begin
  result = 10 / 0
rescue ZeroDivisionError => e
  puts "Caught: #{e.message}"   # Caught: divided by 0
end

# Multiple rescue clauses
def parse_input(input)
  begin
    Integer(input)      # raises ArgumentError if not a valid integer
  rescue ArgumentError
    puts "Not a valid integer"
    nil
  rescue TypeError
    puts "Wrong type entirely"
    nil
  end
end

# else — runs if no exception raised
# ensure — always runs (like finally)
def read_file(path)
  f = File.open(path)
  content = f.read
rescue Errno::ENOENT => e
  puts "File not found: #{e.message}"
  nil
else
  puts "Read #{content.length} bytes successfully"
  content
ensure
  f&.close   # &. is the safe navigation operator — only calls close if f is not nil
end
Ruby
# Custom exceptions
class InsufficientFundsError < StandardError
  attr_reader :amount, :balance

  def initialize(amount, balance)
    @amount  = amount
    @balance = balance
    super("Cannot withdraw $#{amount}. Current balance: $#{balance}")
  end
end

class BankAccount
  def initialize(balance)
    @balance = balance
  end

  def withdraw(amount)
    raise ArgumentError, "Amount must be positive" unless amount > 0
    raise InsufficientFundsError.new(amount, @balance) if amount > @balance
    @balance -= amount
    @balance
  end
end

account = BankAccount.new(100)

begin
  account.withdraw(200)
rescue InsufficientFundsError => e
  puts e.message
  puts "Tried to withdraw: $#{e.amount}"
rescue ArgumentError => e
  puts "Bad input: #{e.message}"
end

# retry — re-attempt the begin block
attempts = 0
begin
  attempts += 1
  raise "Temporary error" if attempts < 3
  puts "Succeeded on attempt #{attempts}"
rescue RuntimeError
  retry if attempts < 3
  puts "Failed after 3 attempts"
end
◆ Note
Rescue without a class catches StandardError and its descendants — which covers almost all application errors. Never rescue Exception (the base class) — it catches things like SignalException (Ctrl+C) and SystemExit, which should be allowed to propagate.