GGistDev

Exception Handling in Ruby

Gracefully manage errors with begin/rescue/ensure and custom exceptions.

Basics and hierarchy

Wrap risky code in begin/rescue; ensure always runs. Most application errors inherit from StandardError.

begin
  risky()
rescue StandardError => e
  warn e.message
ensure
  cleanup()
end

Rescue specific exceptions

Rescue the narrowest class you can; multiple rescues are allowed. A bare rescue catches StandardError only (not Exception).

begin
  Integer("x")
rescue ArgumentError
  :bad_input
rescue => e  # StandardError and subclasses
  :unknown
end

Else and ensure

else runs only if no exception was raised; ensure runs regardless.

begin
  result = compute()
else
  log_success(result)
ensure
  close_resources()
end

Retry (use cautiously)

You can retry the begin block from within a rescue—avoid infinite loops; add backoff/limits.

attempts = 0
begin
  attempts += 1
  fetch()
rescue TimeoutError
  retry if attempts < 3
end

Raising and custom errors

Raise built-ins or your own subclasses of StandardError.

class NotFound < StandardError; end

def fetch!(id)
  raise NotFound, "id=#{id}" unless exists?(id)
  find(id)
end

Inline rescue

Useful for small guards; don’t overuse because it can hide errors.

value = Integer(param) rescue nil

Backtraces and logging

Use e.backtrace (array of strings) to log stack traces; prefer structured logging when possible.

Summary

  • Rescue specific exceptions; avoid blanket catches
  • Use ensure for cleanup and else for success-only paths; consider retry with caution
  • Define custom errors for domain-specific failures; raise informative messages