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.
When an error occurs, most system functions return an error code, usually 0, NULL, or –1. Many system functions also set an additional error code called the last-error code. This error code is maintained separately for each running thread; an error in one thread does not overwrite the last-error code in another thread.
You may notice Error:2 on your player from time to time if you've had a live stream or video running for a long time. It may be that your network/internet connection was briefly interrupted. First, try to refresh the page in your browser. This will usually solve the problem.
The 32bits in an HRESULT error code have meanings, allowing the reader to gain additional insights into the error. Of note: The 32nd bit (the top bit) indicates if an error occurred or not. This is why errors are 0x8xxxxxxx.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With