I am trying to write a function that would be able to catch any type of error, but I am a having some trouble with dplyr::select()
(but also others). For instance, sometimes the error message can be found under $parent$message
but sometimes under $message
:
rlang::catch_cnd(dplyr::filter(mtcars, bm == 1))$parent$message
#> [1] "object 'bm' not found"
rlang::catch_cnd(dplyr::arrange(mtcars, bm))$parent$message
#> [1] "object 'bm' not found"
# But sometimes it's $message and not $parent$message
rlang::catch_cnd(dplyr::group_by(mtcars, bm))$message
#>
#> "Must group by variables found in `.data`."
rlang::catch_cnd(dplyr::count(mtcars, bm))$message
#>
#> "Must group by variables found in `.data`."
And sometimes I have no idea where to look for, for instance in the case of select()
:
rlang::catch_cnd(dplyr::select(mtcars, bm))$message
#> [1] ""
rlang::catch_cnd(dplyr::select(mtcars, bm))$parent$message
#> NULL
Interestingly, the message under $message
is the empty string and not NULL. Looking at the structure of a failed select
call does not help:
str(
rlang::catch_cnd(dplyr::select(mtcars, bm))
)
#> List of 9
#> $ message : chr ""
#> $ trace :Classes 'rlang_trace', 'rlib_trace', 'tbl' and 'data.frame': 35 obs. of 5 variables:
#> ..$ call :List of 35
#> .. ..$ : language str(rlang::catch_cnd(dplyr::select(mtcars, bm)))
#> .. ..$ : language rlang::catch_cnd(dplyr::select(mtcars, bm))
#> .. ..$ : language eval_bare(rlang::expr(tryCatch(!!!handlers, { force(expr) ...
#> .. ..$ : language tryCatch(condition = `<fn>`, { force(expr) ...
#> .. ..$ : language tryCatchList(expr, classes, parentenv, handlers)
#> .. ..$ : language tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> .. ..$ : language doTryCatch(return(expr), name, parentenv, handler)
#> .. ..$ : language force(expr)
#> .. ..$ : language dplyr::select(mtcars, bm)
#> .. ..$ : language select.data.frame(mtcars, bm)
#> .. ..$ : language tidyselect_fix_call(tidyselect::eval_select(expr(c(...)), .data), call = error_call)
#> .. ..$ : language withCallingHandlers(expr, error = function(cnd) { cnd$call <- call ...
#> .. ..$ : language tidyselect::eval_select(expr(c(...)), .data)
#> .. ..$ : language eval_select_impl(data, names(data), as_quosure(expr, env), include = include, exclude = exclude, strict = st| __truncated__ ...
#> .. ..$ : language with_subscript_errors(vars_select_eval(vars, expr, strict = strict, data = x, name_spec = name_spec, uniquel| __truncated__ ...
#> .. ..$ : language tryCatch(with_entraced_errors(expr), vctrs_error_subscript = function(cnd) { cnd$subscript_action <- subscript_action(type) ...
#> .. ..$ : language tryCatchList(expr, classes, parentenv, handlers)
#> .. ..$ : language tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> .. ..$ : language doTryCatch(return(expr), name, parentenv, handler)
#> .. ..$ : language with_entraced_errors(expr)
#> .. ..$ : language try_fetch(expr, simpleError = function(cnd) { abort(conditionMessage(cnd), call = conditionCall(cnd)) ...
#> .. ..$ : language withCallingHandlers(expr, simpleError = function(cnd) { { ...
#> .. ..$ : language vars_select_eval(vars, expr, strict = strict, data = x, name_spec = name_spec, uniquely_named = uniquely_nam| __truncated__ ...
#> .. ..$ : language walk_data_tree(expr, data_mask, context_mask, error_call)
#> .. ..$ : language eval_c(expr, data_mask, context_mask)
#> .. ..$ : language reduce_sels(node, data_mask, context_mask, init = init)
#> .. ..$ : language walk_data_tree(new, data_mask, context_mask)
#> .. ..$ : language as_indices_sel_impl(out, vars = vars, strict = strict, data = data, call = error_call)
#> .. ..$ : language as_indices_impl(x, vars, call = call, strict = strict)
#> .. ..$ : language chr_as_locations(x, vars, call = call)
#> .. ..$ : language vctrs::vec_as_location(x, n = length(vars), names = vars)
#> .. ..$ : language `<fn>`()
#> .. ..$ : language stop_subscript_oob(i = i, subscript_type = subscript_type, names = names, subscript_action = subscript_actio| __truncated__
#> .. ..$ : language stop_subscript(class = "vctrs_error_subscript_oob", i = i, subscript_type = subscript_type, ...)
#> .. ..$ : language abort(class = c(class, "vctrs_error_subscript"), i = i, ...)
#> ..$ parent : int [1:35] 0 0 2 2 4 5 6 2 0 0 ...
#> ..$ visible : logi [1:35] TRUE TRUE TRUE TRUE TRUE TRUE ...
#> ..$ namespace: chr [1:35] "utils" "rlang" "rlang" "base" ...
#> ..$ scope : chr [1:35] "::" "::" "::" "::" ...
#> ..- attr(*, "version")= int 2
#> $ i : chr "bm"
#> $ subscript_type : chr "character"
#> $ names : chr [1:11] "mpg" "cyl" "disp" "hp" ...
#> $ subscript_action: chr "subset"
#> $ subscript_arg : chr ""
#> $ call : language dplyr::select(mtcars, bm)
#> $ subscript_elt : chr "column"
#> - attr(*, "class")= chr [1:5] "vctrs_error_subscript_oob" "vctrs_error_subscript" "rlang_error" "error" ...
What would be the best way to consistently catch the error messages, for ANY function, regardless if it's a dplyr (or generally speaking a tidyverse) verb or a base function?