@@ -200,34 +200,40 @@ invoke_option_error_handler <- function() {
200200 handler <- as.expression(list (handler ))
201201 }
202202
203+ delayedAssign(" non_local_return" , return ())
204+
203205 for (hnd in handler ) {
204- err <- tryCatch(
206+ # Use `withCallingHandlers()` instead of `tryCatch()` to avoid making
207+ # the call stack too complex. We might be running `options(error = browser())`
208+ withCallingHandlers(
205209 {
206- eval(hnd , globalenv())
207- NULL
210+ # Evaluate from a promise to keep a simple call stack.
211+ # We do evaluate from a closure wrapped in `handler()` so that R
212+ # can infer a named call, for instance in the "Called from:"
213+ # output of `browser()`.
214+ error_handler <- eval(bquote(function () .(hnd )))
215+ error_handler()
208216 },
209- error = identity
217+ error = function (err ) {
218+ # Disable error handler to avoid cascading errors
219+ options(error = NULL )
220+
221+ # We don't let the error propagate to avoid a confusing sequence of
222+ # error messages from R, such as "Error during wrapup"
223+ writeLines(
224+ c(
225+ " The `getOption(\" error\" )` handler failed." ,
226+ " This option was unset to avoid cascading errors." ,
227+ " Caused by:" ,
228+ conditionMessage(err )
229+ ),
230+ con = stderr()
231+ )
232+
233+ # Bail early
234+ non_local_return
235+ }
210236 )
211-
212- if (! is.null(err )) {
213- # Disable error handler to avoid cascading errors
214- options(error = NULL )
215-
216- # We don't let the error propagate to avoid a confusing sequence of
217- # error messages from R, such as "Error during wrapup"
218- writeLines(
219- c(
220- " The `getOption(\" error\" )` handler failed." ,
221- " This option was unset to avoid cascading errors." ,
222- " Caused by:" ,
223- conditionMessage(err )
224- ),
225- con = stderr()
226- )
227-
228- # Bail early
229- return ()
230- }
231237 }
232238}
233239
0 commit comments