Exception: Exception
Overview
Class Exception
and its subclasses are used to indicate that an error or other problem has occurred, and may need to be handled. See s
.
An Exception
object carries certain information:
-
The type (the exception’s class), commonly StandardError, RuntimeError, or a subclass of one or the other; see
Built-In Class Hierarchy
. -
An optional descriptive message; see methods ::new, #message.
-
Optional backtrace information; see methods #backtrace, #backtrace_locations, #set_backtrace.
-
An optional cause; see method #cause.
Built-In Exception Class Hierarchy
The hierarchy of built-in subclasses of class Exception
:
-
-
LoadError
-
NotImplementedError
-
SyntaxError
-
-
-
Interrupt
-
-
-
ArgumentError
-
UncaughtThrowError
-
-
EncodingError
-
FiberError
-
IOError
-
EOFError
-
-
IndexError
-
KeyError
-
StopIteration
-
ClosedQueueError
-
-
-
LocalJumpError
-
NameError
-
NoMethodError
-
-
RangeError
-
FloatDomainError
-
-
RegexpError
-
RuntimeError
-
FrozenError
-
-
SystemCallError
-
Errno (and its subclasses, representing system errors)
-
-
ThreadError
-
TypeError
-
ZeroDivisionError
-
Class Attribute Summary
-
.to_tty? ⇒ Boolean
readonly
Returns
true
if exception messages will be sent to a terminal device.
Class Method Summary
-
.exception(message = nil) ⇒ self, Exception
Returns an exception object of the same class as
self
; useful for creating a similar exception, but with a different message. -
.new(message = nil) ⇒ Exception
constructor
Returns a new exception object.
Instance Method Summary
-
#==(object) ⇒ Boolean
Returns whether
object
is the same class asself
and its #message and #backtrace are equal to those ofself
. -
#backtrace ⇒ Array?
Returns the backtrace (the list of code locations that led to the exception), as an array of strings.
-
#backtrace_locations ⇒ Array?
Returns the backtrace (the list of code locations that led to the exception), as an array of
::Thread::Backtrace::Location
instances. -
#cause ⇒ Exception?
Returns the previous value of global variable
$!
, which may benil
(seeGlobal Variables
): -
#detailed_message(highlight: false, **kwargs) ⇒ String
Returns the message string with enhancements:
-
#exception(message = nil) ⇒ self, Exception
Returns an exception object of the same class as
self
; useful for creating a similar exception, but with a different message. -
#full_message(highlight: true, order: :top) ⇒ String
Returns an enhanced message string:
-
#inspect ⇒ String
Returns a string representation of
self
: -
#message ⇒ String
Returns #to_s.
-
#set_backtrace(value) ⇒ value
Sets the backtrace value for
self
; returns the givenvalue
. -
#to_s ⇒ String
Returns a string representation of
self
:
Constructor Details
.new(message = nil) ⇒ Exception
Returns a new exception object.
The given #message should be a string-convertible object
; see method #message; if not given, the message is the class name of the new instance (which may be the name of a subclass):
Examples:
Exception.new # => #<Exception: Exception>
LoadError.new # => #<LoadError: LoadError> # Subclass of Exception.
Exception.new('Boom') # => #<Exception: Boom>
# File 'error.c', line 1517
static VALUE exc_initialize(int argc, VALUE *argv, VALUE exc) { VALUE arg; arg = (!rb_check_arity(argc, 0, 1) ? Qnil : argv[0]); return exc_init(exc, arg); }
Class Attribute Details
.to_tty? ⇒ Boolean
(readonly)
Returns true
if exception messages will be sent to a terminal device.
# File 'error.c', line 1619
static VALUE exc_s_to_tty_p(VALUE self) { return RBOOL(rb_stderr_tty_p()); }
Class Method Details
.exception(message = nil) ⇒ self
, Exception
Returns an exception object of the same class as self
; useful for creating a similar exception, but with a different message.
With #message nil
, returns self
:
x0 = StandardError.new('Boom') # => #<StandardError: Boom>
x1 = x0.exception # => #<StandardError: Boom>
x0.__id__ == x1.__id__ # => true
With string-convertible object
#message (even the same as the original message), returns a new exception object whose class is the same as self
, and whose message is the given #message:
x1 = x0.exception('Boom') # => #<StandardError: Boom>
x0..equal?(x1) # => false
Instance Method Details
#==(object) ⇒ Boolean
Returns whether object
is the same class as self
and its #message and #backtrace are equal to those of self
.
# File 'error.c', line 2181
static VALUE exc_equal(VALUE exc, VALUE obj) { VALUE mesg, backtrace; if (exc == obj) return Qtrue; if (rb_obj_class(exc) != rb_obj_class(obj)) { int state; obj = rb_protect(try_convert_to_exception, obj, &state); if (state || UNDEF_P(obj)) { rb_set_errinfo(Qnil); return Qfalse; } if (rb_obj_class(exc) != rb_obj_class(obj)) return Qfalse; mesg = rb_check_funcall(obj, id_message, 0, 0); if (UNDEF_P(mesg)) return Qfalse; backtrace = rb_check_funcall(obj, id_backtrace, 0, 0); if (UNDEF_P(backtrace)) return Qfalse; } else { mesg = rb_attr_get(obj, id_mesg); backtrace = exc_backtrace(obj); } if (!rb_equal(rb_attr_get(exc, id_mesg), mesg)) return Qfalse; return rb_equal(exc_backtrace(exc), backtrace); }
#backtrace ⇒ Array?
Returns the backtrace (the list of code locations that led to the exception), as an array of strings.
Example (assuming the code is stored in the file named t.rb
):
def division(numerator, denominator)
numerator / denominator
end
begin
division(1, 0)
rescue => ex
p ex.backtrace
# ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
loc = ex.backtrace.first
p loc.class
# String
end
The value returned by this method migth be adjusted when raising (see Kernel.raise), or during intermediate handling by #set_backtrace.
See also #backtrace_locations that provide the same value, as structured objects. (Note though that two values might not be consistent with each other when backtraces are manually adjusted.)
see Backtraces
.
# File 'error.c', line 1896
static VALUE exc_backtrace(VALUE exc) { VALUE obj; obj = rb_attr_get(exc, id_bt); if (rb_backtrace_p(obj)) { obj = rb_backtrace_to_str_ary(obj); /* rb_ivar_set(exc, id_bt, obj); */ } return obj; }
#backtrace_locations ⇒ Array?
Returns the backtrace (the list of code locations that led to the exception), as an array of ::Thread::Backtrace::Location
instances.
Example (assuming the code is stored in the file named t.rb
):
def division(numerator, denominator)
numerator / denominator
end
begin
division(1, 0)
rescue => ex
p ex.backtrace_locations
# ["t.rb:2:in 'Integer#/'", "t.rb:2:in 'Object#division'", "t.rb:6:in '<main>'"]
loc = ex.backtrace_locations.first
p loc.class
# Thread::Backtrace::Location
p loc.path
# "t.rb"
p loc.lineno
# 2
p loc.label
# "Integer#/"
end
The value returned by this method might be adjusted when raising (see Kernel.raise), or during intermediate handling by #set_backtrace.
See also #backtrace that provide the same value as an array of strings. (Note though that two values might not be consistent with each other when backtraces are manually adjusted.)
See Backtraces
.
# File 'error.c', line 1972
static VALUE exc_backtrace_locations(VALUE exc) { VALUE obj; obj = rb_attr_get(exc, id_bt_locations); if (!NIL_P(obj)) { obj = rb_backtrace_to_location_ary(obj); } return obj; }
#cause ⇒ Exception
?
Returns the previous value of global variable $!
, which may be nil
(see Global Variables
):
begin
raise('Boom 0')
rescue => x0
puts "Exception: #{x0}; $!: #{$!}; cause: #{x0.cause.inspect}."
begin
raise('Boom 1')
rescue => x1
puts "Exception: #{x1}; $!: #{$!}; cause: #{x1.cause}."
begin
raise('Boom 2')
rescue => x2
puts "Exception: #{x2}; $!: #{$!}; cause: #{x2.cause}."
end
end
end
Output:
Exception: Boom 0; $!: Boom 0; cause: nil.
Exception: Boom 1; $!: Boom 1; cause: Boom 0.
Exception: Boom 2; $!: Boom 2; cause: Boom 1.
# File 'error.c', line 2160
static VALUE exc_cause(VALUE exc) { return rb_attr_get(exc, id_cause); }
#detailed_message(highlight: false, **kwargs) ⇒ String
Returns the message string with enhancements:
-
Includes the exception class name in the first line.
-
If the value of keyword
highlight
istrue
, includes bolding and underlining ANSI codes (see below) to enhance the appearance of the message.
Examples:
begin
1 / 0
rescue => x
p x.
p x. # Class name added.
p x. (highlight: true) # Class name, bolding, and underlining added.
end
Output:
"divided by 0"
"divided by 0 (ZeroDivisionError)"
"\e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m"
This method is overridden by some gems in the Ruby standard library to add information:
-
DidYouMean::Correctable#detailed_message
. -
ErrorHighlight::CoreExt#detailed_message
. -
SyntaxSuggest#detailed_message
.
An overriding method must be tolerant of passed keyword arguments, which may include (but may not be limited to):
-
:highlight
. -
:did_you_mean
. -
:error_highlight
. -
:syntax_suggest
.
An overriding method should also be careful with ANSI code enhancements; see Messages
.
# File 'error.c', line 1808
static VALUE exc_detailed_message(int argc, VALUE *argv, VALUE exc) { VALUE opt; rb_scan_args(argc, argv, "0:", &opt); VALUE highlight = check_highlight_keyword(opt, 0); extern VALUE rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight); return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), RTEST(highlight)); }
#exception(message = nil) ⇒ self
, Exception
Returns an exception object of the same class as self
; useful for creating a similar exception, but with a different message.
With #message nil
, returns self
:
x0 = StandardError.new('Boom') # => #<StandardError: Boom>
x1 = x0.exception # => #<StandardError: Boom>
x0.__id__ == x1.__id__ # => true
With string-convertible object
#message (even the same as the original message), returns a new exception object whose class is the same as self
, and whose message is the given #message:
x1 = x0.exception('Boom') # => #<StandardError: Boom>
x0..equal?(x1) # => false
# File 'error.c', line 1551
static VALUE exc_exception(int argc, VALUE *argv, VALUE self) { VALUE exc; argc = rb_check_arity(argc, 0, 1); if (argc == 0) return self; if (argc == 1 && self == argv[0]) return self; exc = rb_obj_clone(self); rb_ivar_set(exc, id_mesg, argv[0]); return exc; }
#full_message(highlight: true, order: :top) ⇒ String
Returns an enhanced message string:
-
Includes the exception class name.
-
If the value of keyword
highlight
is true (notnil
orfalse
), includes bolding ANSI codes (see below) to enhance the appearance of the message. -
Includes the
backtrace
:-
If the value of keyword
order
is:top
(the default), lists the error message and the innermost backtrace entry first. -
If the value of keyword
order
is:bottom
, lists the error message the the innermost entry last.
-
Example:
def baz
begin
1 / 0
rescue => x
pp x.
pp x. (highlight: false).split("\n")
pp x. .split("\n")
end
end
def ; baz; end
def foo; ; end
foo
Output:
"divided by 0"
["t.rb:3:in 'Integer#/': divided by 0 (ZeroDivisionError)",
"\tfrom t.rb:3:in 'Object#baz'",
"\tfrom t.rb:10:in 'Object#bar'",
"\tfrom t.rb:11:in 'Object#foo'",
"\tfrom t.rb:12:in '<main>'"]
["t.rb:3:in 'Integer#/': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
"\tfrom t.rb:3:in 'Object#baz'",
"\tfrom t.rb:10:in 'Object#bar'",
"\tfrom t.rb:11:in 'Object#foo'",
"\tfrom t.rb:12:in '<main>'"]
An overriding method should be careful with ANSI code enhancements; see Messages
.
# File 'error.c', line 1724
static VALUE exc_full_message(int argc, VALUE *argv, VALUE exc) { VALUE opt, str, emesg, errat; VALUE highlight, order; rb_scan_args(argc, argv, "0:", &opt); highlight = check_highlight_keyword(opt, 1); order = check_order_keyword(opt); { if (NIL_P(opt)) opt = rb_hash_new(); rb_hash_aset(opt, sym_highlight, highlight); } str = rb_str_new2(""); errat = rb_get_backtrace(exc); emesg = rb_get_detailed_message(exc, opt); rb_error_write(exc, emesg, errat, str, opt, highlight, order); return str; }
#inspect ⇒ String
Returns a string representation of self
:
x = RuntimeError.new('Boom')
x.inspect # => "#<RuntimeError: Boom>"
x = RuntimeError.new
x.inspect # => "#<RuntimeError: RuntimeError>"
# File 'error.c', line 1835
static VALUE exc_inspect(VALUE exc) { VALUE str, klass; klass = CLASS_OF(exc); exc = rb_obj_as_string(exc); if (RSTRING_LEN(exc) == 0) { return rb_class_name(klass); } str = rb_str_buf_new2("#<"); klass = rb_class_name(klass); rb_str_buf_append(str, klass); if (RTEST(rb_str_include(exc, rb_str_new2("\n")))) { rb_str_catf(str, ":%+"PRIsVALUE, exc); } else { rb_str_buf_cat(str, ": ", 2); rb_str_buf_append(str, exc); } rb_str_buf_cat(str, ">", 1); return str; }
#message ⇒ String
Returns #to_s.
See Messages
.
# File 'error.c', line 1757
static VALUE exc_message(VALUE exc) { return rb_funcallv(exc, idTo_s, 0, 0); }
#set_backtrace(value) ⇒ value
Sets the backtrace value for self
; returns the given value
.
The value
might be:
-
an array of Thread::Backtrace::Location;
-
an array of
::String
instances; -
a single
::String
instance; or -
nil
.
Using array of ::Thread::Backtrace::Location
is the most consistent option: it sets both #backtrace and #backtrace_locations. It should be preferred when possible. The suitable array of locations can be obtained from Kernel.caller_locations, copied from another error, or just set to the adjusted result of the current error’s #backtrace_locations:
require 'json'
def parse_payload(text)
JSON.parse(text) # test.rb, line 4
rescue JSON::ParserError => ex
ex.set_backtrace(ex.backtrace_locations[2...])
raise
end
parse_payload('{"wrong: "json"')
# test.rb:4:in 'Object#parse_payload': unexpected token at '{"wrong: "json"' (JSON::ParserError)
#
# An error points to the body of parse_payload method,
# hiding the parts of the backtrace related to the internals
# of the "json" library
# The error has both #backtace and #backtrace_locations set
# consistently:
begin
parse_payload('{"wrong: "json"')
rescue => ex
p ex.backtrace
# ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
p ex.backtrace_locations
# ["test.rb:4:in 'Object#parse_payload'", "test.rb:20:in '<main>'"]
end
When the desired stack of locations is not available and should be constructed from scratch, an array of strings or a singular string can be used. In this case, only {#backtrace} is affected:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(["dsl.rb:34", "framework.rb:1"])
# The error have the new value in #backtrace:
p ex.backtrace
# ["dsl.rb:34", "framework.rb:1"]
# but the original one in #backtrace_locations
p ex.backtrace_locations
# [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
end
parse_payload('{"wrong: "json"')
Calling {#set_backtrace} with {nil} clears up {#backtrace} but doesn’t affect {#backtrace_locations}:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(nil)
p ex.backtrace
# nil
p ex.backtrace_locations
# [".../json/common.rb:221:in 'JSON::Ext::Parser.parse'", ...]
end
parse_payload('{"wrong: "json"')
On reraising of such an exception, both {#backtrace} and {#backtrace_locations} is set to the place of reraising:
def parse_payload(text)
JSON.parse(text)
rescue JSON::ParserError => ex
ex.set_backtrace(nil)
raise # test.rb, line 7
end
begin
parse_payload('{"wrong: "json"')
rescue => ex
p ex.backtrace
# ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
p ex.backtrace_locations
# ["test.rb:7:in 'Object#parse_payload'", "test.rb:11:in '<main>'"]
end
See {exceptions.md@Backtraces Backtraces}.
# File 'error.c', line 2108
static VALUE exc_set_backtrace(VALUE exc, VALUE bt) { VALUE btobj = rb_location_ary_to_backtrace(bt); if (RTEST(btobj)) { rb_ivar_set(exc, id_bt, btobj); rb_ivar_set(exc, id_bt_locations, btobj); return bt; } else { return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt)); } }
#to_s ⇒ String
Returns a string representation of self
:
x = RuntimeError.new('Boom')
x.to_s # => "Boom"
x = RuntimeError.new
x.to_s # => "RuntimeError"
# File 'error.c', line 1577
static VALUE exc_to_s(VALUE exc) { VALUE mesg = rb_attr_get(exc, idMesg); if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc)); return rb_String(mesg); }