I can get the last calculated value using .Last.value
2 + 2
## [1] 4
.Last.value
## [1] 4
I can access the latest warnings using last.warning
.
warning("!!!")
## Warning message:
## !!!
last.warning
## $`!!!`
## NULL
I can get the text of the latest error message using geterrmessage()
stop("!!!")
## Error: !!!
geterrmessage()
## [1] "Error: !!!\n"
If I know in advance that an error might be thrown I can use tryCatch
to return the error object.
tryCatch(stop("!!!"), error = identity)
## <simpleError in doTryCatch(return(expr), name, parentenv, handler): !!!>
How can I retrieve the last error as an object, after it has been thrown?
For example, if I type
stop("!!!")
Then I want to be able to type getlasterror()
or similar and retrieve a simpleError
object.
In cases where you are the author of the code, the modern way to solve this is to use the rlang
package. You throw errors using abort()
, then retrieve the last error with last_error()
.
library(rlang)
f <- function() {
abort("@@@")
}
f()
## Error: @@@
last_error()
## <error>
## message: @@@
## class: `rlang_error`
## backtrace:
## ─base::withCallingHandlers(...)
## ─global::f()
## Call `summary(rlang::last_error())` to see the full backtrace
g <- function() {
msg <- "###"
abort(msg)
}
g()
## Error: ###
last_error()
## <error>
## message: ###
## class: `rlang_error`
## backtrace:
## ─base::withCallingHandlers(...)
## ─global::g()
## Call `summary(rlang::last_error())` to see the full backtrace
h <- function() {
err_fn <- abort
err_fn("$$$")
}
h()
## Error: $$$
last_error()
## <error>
## message: $$$
## class: `rlang_error`
## backtrace:
## ─base::withCallingHandlers(...)
## ─global::h()
## Call `summary(rlang::last_error())` to see the full backtrace
The limitation of this is that it doesn't work with errors generated by stop()
.
Based upon David Arenburg's comment, you can use tryCatch()
in conjunction with the traceback.
get_last_error <- function()
{
tr <- .traceback()
if(length(tr) == 0)
{
return(NULL)
}
tryCatch(eval(parse(text = tr[[1]])), error = identity)
}
Examples:
# before an error is thrown
get_last_error()
## NULL
# after an error at the top level
stop("!!!")
## Error: !!!
get_last_error()
## <simpleError in eval(expr, envir, enclos): !!!>
# after an error inside a function
f <- function() stop("@@@")
f()
## Error in f() : @@@
get_last_error()
## <simpleError in eval(expr, envir, enclos): @@@>
A limitation:
When you re-evaluate the error code, all the variables need to be available. So the following examples don't work, for example:
g <- function()
{
msg <- "###"
stop(msg)
}
g()
## Error in g() : ###
get_last_error()
## <simpleError in stop(msg): object 'msg' not found>
h <- function()
{
err_fn <- stop
err_fn("$$$")
}
h()
## Error in h() : $$$
get_last_error()
## <simpleError in eval(expr, envir, enclos): could not find function "err_fn">
By setting options(error = dump.frames)
, the call stack at the time of an error is stored in a variable named last.dump
in the global environment. The environment last.dump[length(last.dump)]
sometimes contains the error object, and sometimes contains the arguments that would create the error.
debugger(last.dump)
allows interactive post-mortem exploration of the stack, as an alternative to having the error object.