Custom Exceptions in Ruby
Fast recall
Quick revision
Core answer
StandardError and gives a domain failure a stable, meaningful type. Define it like any class, optionally store structured context, and raise an instance where the rule is violated. Callers can then rescue that precise error without accidentally swallowing unrelated programming or infrastructure failures.Whether you know a custom exception inherits from StandardError, is raised with raise, and rescued by class so callers act on the real cause.
Inheriting from Exception (not StandardError) — won't be caught by default rescue; or rescuing a generic StandardError instead of the specific class.
Define a custom exception as class X < StandardError. raise X, 'msg'; rescue X => e. Keep under StandardError; callers rescue YOUR error specifically.
Interview-ready guide
Interview answer
A custom exception is a Ruby class that gives one meaningful application failure a stable type. It normally inherits from StandardError, for example class InsufficientFundsError < StandardError; end. Callers can then rescue that precise condition instead of inspecting message text or accidentally treating database and programming failures as the same business problem.
The class may be empty when its name is enough. When a handler needs details, add readers such as available and requested, set them in initialize, and call super(message) so normal exception logging and error.message still work. Structured attributes remain reliable when display wording changes and avoid parsing values back out of prose.
Raise the exception at the layer that can truthfully name the violated rule. An Account knows whether a withdrawal exceeds its balance, while a controller usually does not own that calculation. The runnable example leaves the balance unchanged, raises one structured object, and lets the caller read its type, message, and fields without swallowing another category of failure.
A separate class is valuable when callers react differently, the failure crosses layers, or a group of related errors needs a shared parent such as PaymentError. Keep that hierarchy shallow and based on handling behavior. Rescue the error only where the program can translate, recover, or add context; otherwise let it propagate with its original meaning.
Custom Exceptions in Ruby
Direct Answer
A custom Ruby exception is a class that normally inherits from StandardError and gives a domain failure a stable, meaningful type. Define it like any class, optionally store structured context, and raise an instance where the rule is violated. Callers can then rescue that precise error without accidentally swallowing unrelated programming or infrastructure failures.
Deep Dive & Architecture
A message explains a failure to a human; a class lets code identify it reliably. Testing whether error.message contains a phrase is fragile because wording changes and translations break the condition. Rescuing InsufficientFundsError expresses the intended contract directly.
The raising layer should own the meaning. A repository may raise a storage-specific error, while a payment service can translate it into a domain error only when that translation is truthful. The receiving layer then decides whether to show validation feedback, retry, cancel work, or let the error propagate.
Structured attributes keep machine-relevant facts separate from prose. A handler can read error.available and error.requested without parsing the display message. Calling super(message) still initializes the standard exception message and preserves normal message, logging, and backtrace behaviour.
Inheritance can group related conditions: several payment errors may inherit from PaymentError, allowing a boundary to catch the family while inner code catches one subtype. Keep the tree shallow and based on handling behaviour, not an attempt to model every noun in the application.
Code Example
class InsufficientFundsError < StandardError
attr_reader :available, :requested
def initialize(available:, requested:)
@available = available
@requested = requested
super("requested #{requested}, available #{available}")
end
end
class Account
def initialize(balance)
@balance = balance
end
def withdraw(amount)
if amount > @balance
raise InsufficientFundsError.new(
available: @balance, requested: amount
)
end
@balance -= amount
end
end
Common Mistakes & Pitfalls
Inheriting from Exception (not StandardError) — won't be caught by default rescue; or rescuing a generic StandardError instead of the specific class.
Check your understanding
Answer these without looking back at the article.
- Why should application exceptions usually inherit from `StandardError`?
- When should a custom exception contain structured attributes?
- Where should a low-level exception be translated into a domain exception?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.