rubyguides

Kernel#fail

fail([exception [, msg [, backtrace]]]) -> never

fail is a Ruby keyword that raises an exception. It is functionally identical to raise — the two are exact aliases. The only difference is stylistic: some developers prefer fail when indicating a failure condition, while raise is more commonly used for general exception raising.

Use fail when it makes the intent of a guard clause read naturally. The keyword tells the reader that the current operation cannot continue. Because it behaves the same as raise, the choice should follow the style of the surrounding project.

Syntax

fail
fail exception_object
fail "Error message"
fail ExceptionClass, "Error message"
fail ExceptionClass, "Error message", backtrace_array

Parameters

ParameterTypeDefaultDescription
exceptionExceptionRuntimeErrorAn exception instance or class to raise
msgStringexception’s default messageThe error message
backtraceArraycaller backtraceCustom backtrace information

When passed a class (e.g., fail RuntimeError, "message"), Ruby instantiates it with the message.

The argument forms mirror raise, so existing exception classes and custom exception objects work the same way. That makes fail a naming choice, not a separate exception mechanism.

Examples

Basic usage

fail "Something went wrong"
# => RuntimeError: Something went wrong

When no exception class is specified, fail defaults to RuntimeError. This is the most common form in guard clauses and simple error signalling, where the message alone carries enough context for the caller to understand what went wrong and decide how to recover.

Raising a specific exception type

fail ArgumentError, "Invalid input"
# => ArgumentError: Invalid input

Using a specific exception class gives the caller a way to rescue selectively. Rather than catching a generic RuntimeError, the calling code can match ArgumentError and handle it differently from other failure modes. This is especially important in library code where the caller needs fine-grained control over error recovery.

Raising a custom exception instance

class CustomError < StandardError; end
fail CustomError.new("Custom failure")
# => CustomError: Custom failure

Custom exception classes let you attach domain-specific meaning to failures. When a validation check or a business rule is violated, a named exception like InsufficientFundsError is more informative than a plain RuntimeError. The class name itself becomes part of the error contract, making it clear what category of problem occurred.

Using fail in begin/rescue blocks

begin
  fail "Intentional failure"
rescue RuntimeError => e
  puts "Caught: #{e.message}"
end
# Output: Caught: Intentional failure

The rescue block shows that fail raises an exception that can be caught like any other. This is useful when you want to centralise error handling in one place while still using fail to signal problems from deep within the call stack.

Common Patterns

Guard clauses with fail

def process(data)
  fail "Data cannot be nil" if data.nil?
  # ... rest of method
end

The guard clause pattern places the failure check at the top of the method, before any processing logic runs. This keeps the happy path unindented and makes the preconditions explicit. fail reads especially well in this position because it signals that the method cannot proceed under the given conditions.

Fail vs raise — stylistic choice

# Both are identical — pick whichever reads better in context
raise "Connection refused"    # generic
fail "Connection refused"     # suggests operational failure

Consistency matters more than the specific keyword. Mixing both forms without a clear convention can make readers wonder whether there is a semantic difference. In Ruby, there is not.

Errors

ExceptionWhen It Occurs
RuntimeErrorDefault when no exception specified
ArgumentErrorInvalid arguments passed
Any specifiedWhen that specific exception type is raised

When to Use fail

The fail keyword behaves identically to raise, so your choice should be based on code clarity and team conventions:

  • Use fail when signaling an actual failure condition — a guard clause that halts execution because something is wrong
  • Use raise for general exception raising — especially when re-raising or raising from within rescue blocks
# Using fail for failure conditions
def withdraw(amount)
  fail "Insufficient funds" if amount > balance
  # ... process withdrawal
end

# Using raise more generally
def parse(input)
  raise "Invalid format" unless valid?(input)
  # ... parse
rescue
  raise # re-raising preserves the original exception
end

The Ruby style guide does not enforce either form. Many projects pick one and stick with it consistently throughout the codebase.

If your team uses both, a common convention is fail for newly detected invalid states and raise when re-raising or translating an exception. The convention is optional, but documenting it keeps error-handling code easier to scan.

Backtrace Manipulation

You can provide a custom backtrace array as the third argument. This is rarely needed but useful for testing or wrapping external code:

custom_backtrace = ["my_file.rb:10:in 'method'", "my_file.rb:20:in 'caller'"]
fail "Custom error", custom_backtrace

Custom backtraces are rare in application code. They are more useful in tests, adapters, or tools that wrap another execution layer and need the error to point at a caller-friendly location.

See Also