Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`withCallingHandlers` inside `tryCatch` creates uncatchable error

I need to convert a warning to an error to be able to handle it further upstream (warnings are swallowed somewhere in the middle, over which I have no control; errors are not). To do this, I’m doing the following:

warning_to_error = function (expr)
    withCallingHandlers(expr, warning = stop)

This works great:

> warning_to_error(warning('foobar'))
Error in withCallingHandlers(expr, warning = stop) : foobar

Unfortunately, this makes the error completely uncatchable:

> try(warning_to_error(warning('foobar')))
Error in withCallingHandlers(expr, warning = stop) : foobar

In my real situation, there are several layers between my warning_to_error and the try (including the logic that muffles warnings). How can I make the error raised by my calling handler catchable? Unfortunately I cannot use restarts as described in another Stack Overflow question because stop doesn’t define a restart, and I once again have no control over the code doing the catching anyway.

like image 220
Konrad Rudolph Avatar asked Feb 28 '17 10:02

Konrad Rudolph


1 Answers

This should tell you what is happening with your definition of warning_to_error:

> tryCatch(warning_to_error(warning('foobar')), condition = print)
<simpleWarning in withCallingHandlers(expr, warning = stop): foobar>```

As the documentation for stop says, when you call stop with a condition, that condition is signalled to look for handlers, which means warning handlers in this case. If you want an error handler to be invoked you need to signal an error condition. That is what happens when you set options(warn = 2) for example. So you need something like

warning_to_error1 <- function (expr)
    withCallingHandlers(expr,
                        warning = function(w)
                            stop("(converted from warning) ",
                                 conditionMessage(w)))

That gives you

> tryCatch(warning_to_error1(warning('foobar')),
+          error = function(e) print("Got it"))
[1] "Got it"

Ideally we should provide a condition class and constructor for warnings converted to errors and use that internally for warn = 2

like image 67
Luke Tierney Avatar answered Nov 03 '22 06:11

Luke Tierney