Ruby's Exception Hierarchy
Fast recall
Quick revision
Core answer
Exception. Most application failures inherit from StandardError, including RuntimeError, ArgumentError, and NoMethodError; a rescue with no class catches this branch. Process-control and serious runtime conditions such as SystemExit, Interrupt, and NoMemoryError sit outside StandardError, so normal application code should not catch the Exception root.Whether you know Exception is the root, StandardError is the app-error branch (rescue this), and bare rescue catches StandardError.
Rescuing Exception (catches SystemExit/signals), or not knowing bare rescue catches StandardError (not Exception).
Exception is the root; StandardError is the app-error branch (RuntimeError, ArgumentError). rescue catches StandardError by default; don't rescue Exception (catches signals).
Interview-ready guide
Interview answer
Ruby exception objects belong to a class hierarchy rooted at Exception. The important branch for ordinary application failures is StandardError. Familiar classes below it include ArgumentError, RuntimeError, NameError, NoMethodError, and many library-specific errors. The hierarchy lets one rescue clause match either a precise class or a planned family of related failures.
Writing rescue without a class is equivalent to rescue StandardError. It catches ordinary errors while leaving classes such as SystemExit, Interrupt, ScriptError, and NoMemoryError outside the handler. Rescuing the root Exception removes that safety boundary and can stop shutdown or conceal a condition the program cannot repair.
A rescue for a class also matches its descendants, following the same ancestry idea as is_a?. Ruby uses the first matching clause, so rescue JSON::ParserError must appear before rescue StandardError when invalid JSON needs a special response. A broad parent first would consume the same exception and make the later specific handler unreachable in practice.
A class being catchable does not mean the current layer should continue. Rescue the narrowest class whose meaning this layer can translate or recover from, or add context and re-raise it. A top-level job boundary may catch StandardError to record a failed job, while focused business code should normally use smaller domain or library classes.
Ruby's Exception Hierarchy
Direct Answer
Ruby exceptions form a class hierarchy rooted at Exception. Most application failures inherit from StandardError, including RuntimeError, ArgumentError, and NoMethodError; a rescue with no class catches this branch. Process-control and serious runtime conditions such as SystemExit, Interrupt, and NoMemoryError sit outside StandardError, so normal application code should not catch the Exception root.
Deep Dive & Architecture
A rescue clause uses the same ancestry idea as is_a?. If an exception object is an instance of the listed class or one of its descendants, the clause can handle it. This allows a library to publish a parent error for broad boundary handling while still offering subclasses for precise cases.
StandardError is a deliberate safety boundary. Most mistakes in normal input, method calls, files, networks, and application rules live below it. Ruby's default rescue stays on this branch so common error handling does not accidentally consume signals or exit requests.
The order of clauses narrows behaviour. A JSON::ParserError handler can produce an invalid-document response, while a later StandardError handler at a top-level job boundary can record an unexpected job failure. Reversing those clauses would make the specialised response impossible because the parent matches first.
Hierarchy alone does not decide what should be caught. The current layer must be able to restore a valid state, translate the failure for its caller, or add context before re-raising. A class being catchable is not evidence that continuing is safe.
Code Example
require 'json'
def parse_preferences(text)
JSON.parse(text)
rescue JSON::ParserError => error
{ 'error' => "invalid JSON: #{error.message}" }
rescue StandardError => error
warn "unexpected parser failure: #{error.class}"
raise
end
parse_preferences('{bad json}')
# => {"error"=>"invalid JSON: ..."}
Common Mistakes & Pitfalls
Rescuing Exception (catches SystemExit/signals), or not knowing bare rescue catches StandardError (not Exception).
Check your understanding
Answer these without looking back at the article.
- Why does a bare rescue catch `StandardError` but not `Exception`?
- Why must a specific rescue clause appear before its parent class?
- When is a boundary-level `StandardError` rescue reasonable?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.