Question
In Ruby, why is it considered bad style to write code like this?
begin
do_something
rescue Exception => e
puts e.message
end
A Ruby quick reference warns: “Don’t rescue Exception. EVER.” Why is rescuing Exception a problem, and what should be used instead for proper error handling?
Short Answer
By the end of this page, you will understand why rescue Exception is usually too broad in Ruby, how Ruby’s exception hierarchy works, and what you should rescue instead in everyday programs. You will also learn safer patterns for error handling, logging, retries, and validation in real Ruby code.
Concept
Ruby exceptions are organized in a class hierarchy. At the top is Exception, and many different error types inherit from it.
When you write:
rescue Exception => e
you are catching almost everything, including exceptions that usually should not be intercepted by normal application code.
Why this is a problem
Exception includes not only typical program errors, but also system-level and control-flow-related exceptions such as:
SystemExit— raised when the program is trying to exitInterrupt— raised when the user presses Ctrl+CNoMemoryError— raised when memory runs outSignalException— related to operating system signals
If you rescue Exception, your program may:
- ignore shutdown requests
- refuse to stop on Ctrl+C
- hide serious system failures
- continue running in a broken or unsafe state
That makes debugging harder and can create surprising behavior.
What Ruby rescues by default
A plain rescue without specifying a class rescues StandardError, not Exception:
Mental Model
Think of exceptions like alarms in a building.
StandardErroralarms are room-level problems: a broken light, a locked door, a small leak.Exceptionincludes those alarms plus the building fire alarm, evacuation signal, and power failure warnings.
If you silence all alarms, you might also ignore the ones telling everyone to leave the building.
That is what rescue Exception does: it catches not only normal program problems, but also signals that the process should stop or cannot safely continue.
Syntax and Examples
Preferred syntax
In Ruby, these are the common forms:
begin
risky_operation
rescue StandardError => e
puts "Handled: #{e.message}"
end
Or simply:
begin
risky_operation
rescue => e
puts "Handled: #{e.message}"
end
A bare rescue is shorthand for rescuing StandardError.
Better: rescue specific exceptions
begin
number = Integer(user_input)
rescue ArgumentError
puts "Please enter a valid integer"
end
This is better because it only handles the error you actually expect.
Example: too broad
begin
exit
rescue Exception => e
puts "Caught: "
Step by Step Execution
Consider this example:
begin
puts "Start"
number = Integer("abc")
puts "Number: #{number}"
rescue ArgumentError => e
puts "Handled error: #{e.message}"
end
puts "Program continues"
Step-by-step
- Ruby enters the
beginblock. puts "Start"runs.- Ruby executes
Integer("abc"). - Ruby cannot convert
"abc"to an integer. - It raises an
ArgumentError. - Ruby looks for a matching
rescueclause. rescue ArgumentError => ematches the raised exception.- The rescue block runs and prints the error message.
- Execution continues after the
end. puts "Program continues"runs.
Output
Start
Handled error: invalid value for Integer(): "abc"
Program continues
Real World Use Cases
1. Validating user input
begin
age = Integer(params[:age])
rescue ArgumentError, TypeError
age = nil
end
Used when form input may be invalid.
2. Reading files safely
begin
content = File.read("config.txt")
rescue Errno::ENOENT
content = "default config"
end
Used when a file might not exist.
3. Network and API calls
begin
response = api_client.fetch_user(id)
rescue Timeout::Error
puts "Request timed out"
end
Used for temporary failures that can be retried or reported.
4. Background jobs
begin
process_job(job)
rescue => e
logger.error(e.message)
logger.error(e.backtrace.join())
Real Codebase Usage
In real projects, developers rarely want a giant catch-all. They usually use one of these patterns.
Guard clauses before exceptions happen
Instead of rescuing a broad error, check inputs early:
def divide(a, b)
return nil if b == 0
a / b
end
Rescue only expected failures
def parse_port(value)
Integer(value)
rescue ArgumentError, TypeError
3000
end
Log and re-raise when needed
def save_record(record)
record.save!
rescue ActiveRecord::RecordInvalid => e
logger.warn("Validation failed: #{e.message}")
raise
end
This pattern keeps visibility while preserving the original failure.
Wrap low-level errors in domain-specific errors
Common Mistakes
Mistake 1: Rescuing everything
begin
do_work
rescue Exception => e
puts "Something went wrong"
end
Why it is bad
- hides important failures
- catches Ctrl+C interrupts
- may prevent clean shutdown
Better
begin
do_work
rescue StandardError => e
puts "Something went wrong: #{e.message}"
end
Or rescue a specific error class.
Mistake 2: Swallowing errors silently
begin
do_work
rescue => e
end
Why it is bad
The program fails, but you get no clue why.
Better
begin
do_work
rescue => e
warn e.message
raise
end
If you handle an error, do it intentionally.
Mistake 3: Using exceptions for normal control flow
Comparisons
| Approach | What it catches | Typical use | Risk level |
|---|---|---|---|
rescue Exception | Almost all exceptions, including system-level ones | Very rare, special infrastructure code | High |
rescue StandardError | Most normal application errors | General app-level error handling | Medium |
rescue SomeSpecificError | Only the named error type | Best for expected failures | Low |
bare rescue | Same as rescue StandardError | Short form in simple cases | Medium |
Exception vs
Cheat Sheet
Quick rules
- Do not rescue
Exceptionin normal Ruby code. - Use
rescue => eorrescue StandardError => efor general application errors. - Prefer rescuing the specific exception class you expect.
- Log errors when helpful.
- Re-raise errors if you cannot truly handle them.
Common syntax
begin
risky_code
rescue => e
puts e.message
end
begin
risky_code
rescue ArgumentError => e
puts e.message
end
begin
risky_code
rescue ArgumentError, TypeError => e
puts e.message
end
Good defaults
- Expected parse failure:
ArgumentError - Missing file:
Errno::ENOENT - Validation failure: library-specific error
- Generic app boundary:
StandardError
FAQ
Why is rescue Exception bad in Ruby?
Because it catches far more than normal application errors, including SystemExit and Interrupt, which usually should not be blocked.
What should I rescue instead in Ruby?
Usually rescue a specific exception class. If you need a broad catch for app errors, rescue StandardError.
Does bare rescue catch Exception?
No. A bare rescue catches StandardError by default.
Can rescue Exception stop Ctrl+C from working?
Yes. Ctrl+C raises Interrupt, which is under Exception. Rescuing Exception can prevent the program from stopping normally.
Is it ever okay to rescue Exception?
Rarely. It may be used in very low-level framework or process-management code, but it is not appropriate for ordinary application logic.
What is the difference between Exception and ?
Mini Project
Description
Build a small Ruby script that reads a filename from the user, tries to open the file, and converts each line to an integer. This demonstrates how to rescue specific exceptions instead of using Exception, and how to keep different error cases separate and understandable.
Goal
Create a script that safely handles missing files and invalid number input using specific Ruby exception classes.
Requirements
- Ask the user for a filename.
- Read all lines from the file.
- Convert each line to an integer.
- If the file does not exist, print a helpful message.
- If a line is not a valid integer, print which line failed.
- Do not use
rescue Exception.
Keep learning
Related questions
How to Call Shell Commands from Ruby and Capture Output
Learn how to run shell commands in Ruby, capture output, check exit status, and choose the right method for scripts and apps.
How to Check Whether a String Contains a Substring in Ruby
Learn how to check if a string contains a substring in Ruby using include?, match, and multiline string examples.
How to Check if a Hash Key Exists in Ruby
Learn how to check whether a specific key exists in a Ruby hash using key?, has_key?, and include? with clear examples.