Exception: Exception

Inherits:
Object show all
Defined in:
error.c,
error.c

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 Exceptions.

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 Exception 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:

  • NoMemoryError

  • ScriptError

    • LoadError

    • NotImplementedError

    • SyntaxError

  • SecurityError

  • SignalException

    • Interrupt

  • StandardError

    • 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

  • SystemExit

  • SystemStackError

  • fatal

Class Method Summary collapse

Instance Method Summary collapse

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>


1517
1518
1519
1520
1521
1522
1523
1524
# 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 Method Details

.exceptionObject

call-seq:

exception(message = nil) -> self or new_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

.to_tty?Boolean

Returns true if exception messages will be sent to a terminal device.

Returns:

  • (Boolean)


1619
1620
1621
1622
1623
# File 'error.c', line 1619

static VALUE
exc_s_to_tty_p(VALUE self)
{
    return RBOOL(rb_stderr_tty_p());
}

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.

Returns:

  • (Boolean)


2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
# 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);
}

#backtraceArray?

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.

Returns:



1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
# 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_locationsArray?

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.

Returns:



1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
# 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;
}

#causeException?

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.

Returns:



2160
2161
2162
2163
2164
# 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 is true, includes bolding and underlining ANSI codes (see below) to enhance the appearance of the message.

Examples:

begin
  1 / 0
rescue => x
  p x.message
  p x.detailed_message                  # Class name added.
  p x.detailed_message(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.

Returns:



1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
# 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(*args) ⇒ Object

call-seq:

exception(message = nil) -> self or new_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


1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
# 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 (not nil or false), 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.message
    pp x.full_message(highlight: false).split("\n")
    pp x.full_message.split("\n")
  end
end
def bar; baz; end
def foo; bar; 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.

Returns:



1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
# 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;
}

#inspectString

Returns a string representation of self:

x = RuntimeError.new('Boom')
x.inspect # => "#<RuntimeError: Boom>"
x = RuntimeError.new
x.inspect # => "#<RuntimeError: RuntimeError>"

Returns:



1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
# 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;
}

#messageString

Returns #to_s.

See Messages.

Returns:



1757
1758
1759
1760
1761
# File 'error.c', line 1757

static VALUE
exc_message(VALUE exc)
{
    return rb_funcallv(exc, idTo_s, 0, 0);
}

#set_backtrace(value) ⇒ Object

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 Backtraces.



2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
# 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_sString

Returns a string representation of self:

x = RuntimeError.new('Boom')
x.to_s # => "Boom"
x = RuntimeError.new
x.to_s # => "RuntimeError"

Returns:



1577
1578
1579
1580
1581
1582
1583
1584
# 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);
}