22.14 Non-error failures

There are other ways for a function to fail apart from throwing an error:

  • A function may generate an unexpected warning. The easiest way to track down warnings is to convert them into errors with options(warn = 2) and use the the call stack, like doWithOneRestart(), withOneRestart(), regular debugging tools. When you do this you’ll see some extra calls withRestarts(), and .signalSimpleWarning(). Ignore these: they are internal functions used to turn warnings into errors.

  • A function may generate an unexpected message. You can use rlang::with_abort() to turn these messages into errors:

f <- function() g()
g <- function() message("Hi!")
f()
#> Hi!


rlang::with_abort(f(), "message")
#> Error: 'with_abort' is not an exported object from 'namespace:rlang'

rlang::last_trace()
#> <error/purrr_error_indexed>
#> Error in `map_chr()`:
#> ℹ In index: 3.
#> Caused by error:
#> ! Result must be length 1, not 0.
#> ---
#> Backtrace:
#>     ▆
#>  1. └─purrr::map_chr(my_list, "z")
#>  2.   └─purrr:::map_("character", .x, .f, ..., .progress = .progress)
#>  3.     ├─purrr:::with_indexed_errors(...)
#>  4.     │ └─base::withCallingHandlers(...)
#>  5.     └─purrr:::call_with_cleanup(...)
#> Run rlang::last_trace(drop = FALSE) to see 4 hidden frames.
  • A function might never return. This is particularly hard to debug automatically, but sometimes terminating the function and looking at the traceback() is informative. Otherwise, use use print debugging, as in Section 22.5.2.

  • The worst scenario is that your code might crash R completely, leaving you with no way to interactively debug your code. This indicates a bug in compiled (C or C++) code.