Title: Reraise (same exception) after catching an exception in Ruby
Tags: ruby;exception
Question: I am trying to improve my Ruby skills by catching exceptions. I want to know if it is common to reraise the same kind of exception when you have several method calls. So, would the following code make sense? Is it ok to reraise the same kind of exception, or should I not catch it on the process method?
class Logo
def process
begin
@processed_logo = LogoProcessor75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0reate_image(self.src)
rescue CustomException
raise CustomException
end
module LogoProcessor
def self.create_image
raise CustomException if some_condition

Here is the accepted answer: Sometimes we just want to know an error happened, without having to actually handle the error.
It is often the case that the one responsible for handling errors is user of the object: the caller. What if we are interested in the error, but don't want to assume that responsibility? We rescue the error, do whatever we need to do and then propagate the signal up the stack as if nothing had happened.
For example, what if we wanted to log the error message and then let the caller deal with it?
this_will_fail!
rescue Failure =&gt; error
log.error error.message
raise
Calling raise without any arguments will raise the last error. In our case, we are re-raising error.
In the example you presented in your question, re-raising the error is simply not necessary. You could simply let it propagate up the stack naturally. The only difference in your example is you're creating a new error object and raising it instead of re-raising the last one.
Comment for this answer: @RafałCieślak it's not quite as simple as `Every time an error is raised, it is assigned to the $! global variable`; I posted a full explanation [here](https://stackoverflow.com/a/69652924)
Comment for this answer: @HommerSmith : What if the line before raise (log.error in this case, but it could be anything) fails? I'm thinking on "ensuring" it, but, inside the ensure I would need to use the reference to the error as the argument of "raise". What do you think about that?
Comment for this answer: Is that behavior of preserving the backtrace documented somewhere? I couldn't find much about it in the docs. https://docs.ruby-lang.org/en/2.6.0/syntax/exceptions_rdoc.html
Comment for this answer: FYI for other people wondering `raise error` seems to be equivalent to just doing `raise`. I thought that these two are different for some reason – and they would be if I was raising a new error object, but both cases reuse the current error.
Comment for this answer: This would loose the `stacktrace` from the original exception, you probably want to include exception `cause` which is available in ruby > 2.1
Comment for this answer: @bjhaid Calling `raise` in the manner of this answer preserves the original exception entirely, including the `backtrace`. `cause` does not apply to this case. Rather, it gets populated automatically when a `rescue` block raises a new exception.
Comment for this answer: @RafałCieślak Every time an error is raised, it is assigned to the `$!` global variable. Calling `raise` without arguments raises the error contained in `$!`, effectively raising the last error. However, `raise error` will raise the error contained in the `error` local variable, which may or may not be the same object contained in `$!`. In my example, `$!` is the same as `error`. However, it's also possible to do this: `error = Exception.new; raise error`
Comment for this answer: @user2426679 You're correct. It turns out `$!` is not a true global variable. It will always refer to the exception currently being handled and only exists inside the block that's handling it. Thank you for teaching me this! [Here's a demonstration on ideone.](https://ideone.com/Kc8yzP)
Comment for this answer: @RafałCieślak Yes, it is documented in [`Exception#cause`](https://ruby-doc.org/core/Exception.html#method-i-cause) which says the method will return "the previous exception (`$!`) at the time this exception was raised".
Comment for this answer: Interesting. My question is, if I don't catch the error in the definition of process, then I would need to catch it when I call the process method, e.g: ``begin @logo.process; rescue...``, but then I wouldn't be catching an exception launched by process itself, but of something that has been called from within process. Is that correct to do?

Here is another answer: This will raise the same type of error as the original, but you can customize the message.
rescue StandardError =&gt; e
raise e.class, "Message: #{e.message}"
Comment for this answer: Actually the `Exception` class has an `exception` method which allows to do exactly that. See my answer.
Comment for this answer: I believe this is an "exception" to the rule, since we're immediately raising the Exception again.
Comment for this answer: I would suggest its a bad idea to catch StandardError as this includes all kinds of lower level functions and could hang your program.
Comment for this answer: I see what you did there, @FreePender ;)
Comment for this answer: I know it's been a year, but it's safe to catch StandardError, @PaulWhitehead -- it's Exception you must never, ever catch.  (Quick source: https://thoughtbot.com/blog/rescue-standarderror-not-exception )

Here is another answer: I had the same question as in the comment thread here, i.e. What if the line before (re)raise fails?
My understanding was limited by the missing knowledge that the global variable of $! is &quot;kinda garbage collected&quot; // &quot;scoped to its functional context&quot;, which the below example demonstrates:
def func
begin
raise StandardError, 'func!'
rescue StandardError =&gt; err
puts &quot;$! = #{$!.inspect}&quot;
raise StandardError, 'oh no!'
rescue StandardError =&gt; err
func
puts &quot;$! = #{$!.inspect}&quot;
raise
The output of the above is:
$! = #<StandardError: func!&gt;
$! = #<StandardError: oh no!&gt;
StandardError: oh no!
from (pry):47:in `__pry__'
This behavior is different than how Python's (re)raise works.
The documentation for Exception states:
When an exception has been raised but not yet handled (in rescue,
ensure, at_exit and END blocks), two global variables are set:
$! contains the current exception.
$@ contains its backtrace.
So these variables aren't true global variables, they are only defined inside the block that's handling the error.
raise
rescue
p $!  # StandardError
p $!    # nil
Comment for this answer: You're right! It turns out `$!` and `$@` aren't true global variables. They're only defined in `rescue`, `ensure`, `at_exit` and `END` blocks. Thank you for teaching me something today!

Here is another answer: Adding to above answers here:
In some applications you may need to log the error twice.
For example exception need to be notified to monitoring tools like
Nagios/Newrelic/Cloudwatch.
At the same time you may have your own kibana backed summary logging
tool, internally for your reference.
In those cases you might want to log &amp; handle the errors multiple times.
Example:
begin
nil.to_sym
rescue =&gt; e
puts &quot;inner block error message: #{e.message}&quot;
puts &quot;inner block backtrace: #{e.backtrace.join(&quot;\n&quot;)}&quot;
raise e
rescue =&gt; e
puts &quot;outer block error message: #{e.message}&quot;
puts &quot;outer block backtrace: #{e.backtrace.join(&quot;\n&quot;)}&quot;
I am using puts here, for your the ease of verifying this code in
rails console, in actual production you may need to use rails logger

Here is another answer: A slightly better way to do the same thing as FreePender is to use the exception method from the Exception class, which is the ancestor class to any error classes, like StandardError, so that the method is available to any error classes.
Here the method's documentation that you can find on ApiDock:
With no argument, or if the argument is the same as the receiver, return the receiver. Otherwise, create a new exception object of the same class as the receiver, but with a message equal to string.to_str.
Now let's see how it works:
this_will_fail!
rescue Failure =&gt; error
raise error.exception(&quot;Message: #{error.message}&quot;)
Comment for this answer: Note that it won't always work. For example, the `Timeout75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0rror` has this method overriden and it ignores the args.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 5, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2014:00:05/20/14', 'FavoriteCount': 11.0, 'PostTypeId': 1, 'Tags': '<ruby><exception>', 'Title': 'Reraise (same exception) after catching an exception in Ruby', 'ViewCount': 45424, 'id': 23770924, 'user_AboutMe': '', 'user_AccountId': 1231715.0, 'user_DisplayName': 'Hommer Smith', 'user_Reputation': 25452.0, 'user_Views': 1037.0, 'user_id': 1196150.0}}