custom error messages inside a function with tryCatch

Viewed 60

I'm building a package and I want more control over error messages

I've read Hadley's chapter about handling exceptions but I'm still lost

Here is a simple example:

myfunc = function(x){
  intial_result = x + 1
  final_result = initial_result + 1
  return(final_result)
}

if you run myfunc("1") you get the error:

> myfunc("1")
Error in x + 1 : non-numeric argument to binary operator

but that does not tell the user where the error happened.

So I tried to use tryCatch, and it works, sort of:

myfunc = function(x){
  r = tryCatch(
    expr = {x + 1},
    error = function(e){
      message = paste0("argument must be a number", "\nFor example, x = 2")
      e = simpleError(message)
      stop(e)
    }
  )
  r2 = r + 1
  return(r2)
}

But is this the best way to go about a custom error message?

Moreover, is there a way to throw only a message() and still stop() the program? (because stop() will activate the debugger)

EDIT I would love to have error messages like the ones in dplyr:

library(dplyr)
data('starwars')
select(starwars, x)
Error: Can't subset columns that don't exist.
x Column `x` doesn't exist.
Run `rlang::last_error()` to see where the error occur
2 Answers

You might find something like an assert function useful.

In its simplest, it checks if a condition is true and throws an error otherwise.

assert <- function(condition, msg){
  if(condition == FALSE)
    stop(msg)
}

Use example:

myfunc = function(x){
  assert(is.numeric(x), "input 'x' to 'myfunc' was not numeric")
  intial_result = x + 1
  final_result = initial_result + 1
  return(final_result)
}

If this is what you need, there is an entire R package for this purpose: assertthat, from which you probably would want the assert_that function.

dplyr appears to use the assertr package, so you might also want to investigate that.

answer above is good

I poked around the dplyr github repo and saw it uses rlang stuff

this will return a tidyverse style error:

myfunc = function(x){
  initial_result = rlang::with_handlers(
    .expr = x + 1,
    error = ~ rlang::abort(c("you did it wrong", x = "`x` should be a number", i = "For example: `x = 2`")))
  final_result = initial_result + 1
  return(final_result)
}

> myfunc(a)
Error: you did it wrong
x `x` should be a number
i For example: `x = 2`
Run `rlang::last_error()` to see where the error occurred.
Related