Like any R objects, errors captured with catchers like tryCatch()
have a class()
which you can test with inherits()
. However,
with chained errors, the class of a captured error might be
different than the error that was originally signalled. Use
cnd_inherits()
to detect whether an error or any of its parent
inherits from a class.
Whereas inherits()
tells you whether an object is a particular
kind of error, cnd_inherits()
answers the question whether an
object is a particular kind of error or has been caused by such an
error.
Some chained conditions carry parents that are not inherited. See
the .inherit
argument of abort()
, warn()
, and inform()
.
cnd_inherits(cnd, class)
A condition to test.
A class passed to inherits()
.
Error catchers like tryCatch()
and try_fetch()
can only match
the class of a condition, not the class of its parents. To match a
class across the ancestry of an error, you'll need a bit of
craftiness.
Ancestry matching can't be done with tryCatch()
at all so you'll
need to switch to withCallingHandlers()
. Alternatively, you can
use the experimental rlang function try_fetch()
which is able to
perform the roles of both tryCatch()
and withCallingHandlers()
.
withCallingHandlers()
Unlike tryCatch()
, withCallingHandlers()
does not capture an
error. If you don't explicitly jump with an error or a value
throw, nothing happens.
Since we don't want to throw an error, we'll throw a value using
callCC()
:
f <- function() {
parent <- error_cnd("bar", message = "Bar")
abort("Foo", parent = parent)
}cnd <- callCC(function(throw) {
withCallingHandlers(
f(),
error = function(x) if (cnd_inherits(x, "bar")) throw(x)
)
})
class(cnd)
#> [1] "rlang_error" "error" "condition"
class(cnd$parent)
#> [1] "bar" "rlang_error" "error" "condition"
try_fetch()
This pattern is easier with try_fetch()
. Like
withCallingHandlers()
, it doesn't capture a matching error right
away. Instead, it captures it only if the handler doesn't return a
zap()
value.
cnd <- try_fetch(
f(),
error = function(x) if (cnd_inherits(x, "bar")) x else zap()
)class(cnd)
#> [1] "rlang_error" "error" "condition"
class(cnd$parent)
#> [1] "bar" "rlang_error" "error" "condition"
Note that try_fetch()
uses cnd_inherits()
internally. This
makes it very easy to match a parent condition:
cnd <- try_fetch(
f(),
bar = function(x) x
)# This is the parent
class(cnd)
#> [1] "bar" "rlang_error" "error" "condition"