🔍

No recent searches

# class Exception

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`

### Public Class Methods

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

json_create (object)
Source

    # File ext/json/lib/json/add/exception.rb, line 9
    def self.json_create(object)
      result = new(object['m'])
      result.set_backtrace object['b']
      result
    end

See `as_json`.

new(message = nil) → exception
Source

    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);
    }

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>

to_tty? → true or false
Source

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

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

### Public Instance Methods

self == object → true or false
Source

    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);
    }

Returns whether `object` is the same class as `self` and its `message` and `backtrace` are equal to those of `self`.

as_json (*)
Source

    # File ext/json/lib/json/add/exception.rb, line 29
    def as_json(*)
      {
        JSON.create_id => self.class.name,
        'm'            => message,
        'b'            => backtrace,
      }
    end

Methods `Exception#as_json` and `Exception.json_create` may be used to serialize and deserialize a Exception object; see `Marshal`.

Method `Exception#as_json` serializes `self`, returning a 2-element hash representing `self`:

    require 'json/add/exception'
    x = Exception.new('Foo').as_json # => {"json_class"=>"Exception", "m"=>"Foo", "b"=>nil}

Method `JSON.create` deserializes such a hash, returning a Exception object:

    Exception.json_create(x) # => #<Exception: Foo>

backtrace → array or nil
Source

    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;
    }

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

backtrace_locations → array or nil
Source

    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;
    }

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.

cause → exception or nil
Source

    static VALUE
    exc_cause(VALUE exc)
    {
        return rb_attr_get(exc, id_cause);
    }

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.

detailed_message(highlight: false, **kwargs) → string
Source

    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));
    }

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.

exception(message = nil) → self or new_exception
Source

    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;
    }

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

full_message(highlight: true, order: :top) → string
Source

    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;
    }

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

inspect → string
Source

    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;
    }

Returns a string representation of `self`:

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

message → string
Source

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

Returns `to_s`.

See Messages.

set_backtrace(value) → value
Source

    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));
        }
    }

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.

to_json (*args)
Source

    # File ext/json/lib/json/add/exception.rb, line 46
    def to_json(*args)
      as_json.to_json(*args)
    end

Returns a `JSON` string representing `self`:

    require 'json/add/exception'
    puts Exception.new('Foo').to_json

Output:

    {"json_class":"Exception","m":"Foo","b":null}

to_s → string
Source

    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);
    }

Returns a string representation of `self`:

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