How do you make tryCatch actually catch the error - r

I have to call a function that throws an error if the arguments didn't satisfy many conditions.
The conditions are so complicated that I cannot try to satisfy them 100% of the time (I would have to re-type all the conditions the function checks internally).
Instead, I should just retry calling with different arguments (as many times as necessary to fill my table).
In other languages I can write a catch block around the call.
However, in R tryCatch seems to work differently: you can give code with finally=, but after executing the finally-code the outer function terminates anyway.
Here is a minimal example:
sometimesError <- function() {
if(runif(1)<0.1) stop("err")
return(1)
}
fct <- function() {
theSum <- 0
while(theSum < 20) {
tryCatch( theSum <- theSum + sometimesError() )
}
return(theSum)
}
fct() # this should always evaluate to 20, never throw error
( I have read "Is there a way to source() and continue after an error?", and some other posts but I dont think they apply here. They achieve that the source'd code continues statement-by-statement regardless of error as if it were executing at the top level. I, on the other side, am happy with the called function terminating and it is the caller-code that should continue )

You can pass a function to the error argument of tryCatch to specify what should happen when there is an error. In this case, you could just return 0 when there is an error
fct <- function() {
theSum <- 0
while(theSum < 20) {
theSum <- theSum + tryCatch(sometimesError(), error=function(e) 0)
}
return(theSum)
}
As #rawr mentioned in the comments, you could also replace tryCatch with try in this case.
fct <- function() {
theSum <- 0
while(theSum < 20) {
try(theSum <- theSum + sometimesError(), silent=TRUE)
}
return(theSum)
}

Related

How to skip the error file and continue to read the next one when batch reading files in R [duplicate]

I've read a few other SO questions about tryCatch and cuzzins, as well as the documentation:
Exception handling in R
catching an error and then branching logic
How can I check whether a function call results in a warning?
Problems with Plots in Loop
but I still don't understand.
I'm running a loop and want to skip to next if any of a few kinds of errors occur:
for (i in 1:39487) {
# EXCEPTION HANDLING
this.could.go.wrong <- tryCatch(
attemptsomething(),
error=function(e) next
)
so.could.this <- tryCatch(
doesthisfail(),
error=function(e) next
)
catch.all.errors <- function() { this.could.go.wrong; so.could.this; }
catch.all.errors;
#REAL WORK
useful(i); fun(i); good(i);
} #end for
(by the way, there is no documentation for next that I can find)
When I run this, R honks:
Error in value[[3L]](cond) : no loop for break/next, jumping to top level
What basic point am I missing here? The tryCatch's are clearly within the for loop, so why doesn't R know that?
The key to using tryCatch is realising that it returns an object. If there was an error inside the tryCatch then this object will inherit from class error. You can test for class inheritance with the function inherit.
x <- tryCatch(stop("Error"), error = function(e) e)
class(x)
"simpleError" "error" "condition"
Edit:
What is the meaning of the argument error = function(e) e? This baffled me, and I don't think it's well explained in the documentation. What happens is that this argument catches any error messages that originate in the expression that you are tryCatching. If an error is caught, it gets returned as the value of tryCatch. In the help documentation this is described as a calling handler. The argument e inside error=function(e) is the error message originating in your code.
I come from the old school of procedural programming where using next was a bad thing. So I would rewrite your code something like this. (Note that I removed the next statement inside the tryCatch.):
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(!inherits(possibleError, "error")){
#REAL WORK
useful(i); fun(i); good(i);
}
} #end for
The function next is documented inside ?for`.
If you want to use that instead of having your main working routine inside an if, your code should look something like this:
for (i in 1:39487) {
#ERROR HANDLING
possibleError <- tryCatch(
thing(),
error=function(e) e
)
if(inherits(possibleError, "error")) next
#REAL WORK
useful(i); fun(i); good(i);
} #end for
I found other answers very confusing. Here is an extremely simple implementation for anyone who wants to simply skip to the next loop iteration in the event of an error
for (i in 1:10) {
skip_to_next <- FALSE
# Note that print(b) fails since b doesn't exist
tryCatch(print(b), error = function(e) { skip_to_next <<- TRUE})
if(skip_to_next) { next }
}
for (i in -3:3) {
#ERROR HANDLING
possibleError <- tryCatch({
print(paste("Start Loop ", i ,sep=""))
if(i==0){
stop()
}
}
,
error=function(e) {
e
print(paste("Oops! --> Error in Loop ",i,sep = ""))
}
)
if(inherits(possibleError, "error")) next
print(paste(" End Loop ",i,sep = ""))
}
The only really detailed explanation I have seen can be found here: http://mazamascience.com/WorkingWithData/?p=912
Here is a code clip from that blog post showing how tryCatch works
#!/usr/bin/env Rscript
# tryCatch.r -- experiments with tryCatch
# Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1]
# Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
if (a == 'warning') {
return_value <- 'myDivide warning result'
warning("myDivide warning message")
} else if (a == 'error') {
return_value <- 'myDivide error result'
stop("myDivide error message")
} else {
return_value = d / as.numeric(a)
}
return(return_value)
}
# Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({
b <- 2
c <- b^2
d <- c+2
if (a == 'suppress-warnings') {
e <- suppressWarnings(myDivide(d,a))
} else {
e <- myDivide(d,a) # 6/a
}
f <- e + 100
}, warning = function(war) {
# warning handler picks up where error was generated
print(paste("MY_WARNING: ",war))
b <- "changing 'b' inside the warning handler has no effect"
e <- myDivide(d,0.1) # =60
f <- e + 100
return(f)
}, error = function(err) {
# warning handler picks up where error was generated
print(paste("MY_ERROR: ",err))
b <- "changing 'b' inside the error handler has no effect"
e <- myDivide(d,0.01) # =600
f <- e + 100
return(f)
}, finally = {
print(paste("a =",a))
print(paste("b =",b))
print(paste("c =",c))
print(paste("d =",d))
# NOTE: Finally is evaluated in the context of of the inital
# NOTE: tryCatch block and 'e' will not exist if a warning
# NOTE: or error occurred.
#print(paste("e =",e))
}) # END tryCatch
print(paste("result =",result))
One thing I was missing, which breaking out of for loop when running a function inside a for loop in R makes clear, is this:
next doesn't work inside a function.
You need to send some signal or flag (e.g., Voldemort = TRUE) from inside your function (in my case tryCatch) to the outside.
(this is like modifying a global, public variable inside a local, private function)
Then outside the function, you check to see if the flag was waved (does Voldemort == TRUE). If so you call break or next outside the function.

R foreach stop iteration at i

I am using R package foreach.
When bug exists in foreach block, it's hard to re-occur it and hard to debug.
Take the following script as example.
I want to stop at i=4 to check what's wrong. However, it stops at i=10.
Any solution?
library(foreach)
foreach(i = icount(10)) %do% {
if (i == 4){
e <- simpleError("test error")
stop(e)
}
}
One option to handle this is with a browser() inside a tryCatch as in:
foreach(i = icount(10)) %do% {
tryCatch(
if (i == 4){
e <- simpleError("test error")
stop(e)
},
error = function(e) browser()
)
}
This will produce a browser of the environment at the time of the error, which will allow you to inspect any objects and/or debug your code.
Your console will then look like the following and you can ask what the value of i is. Like this:
Browse[1]> i
[1] 4

Specify the calling function for an error message in R

I'm working on an R package where the same input-checking functions are called by multiple "actual" functions that are exported to users. If I use a simple stop() call, the error message is going to say that an error occurred in the input-checking function, which is not that useful...
I thought I'd get around this by wrapping the call to the input-checking function inside a tryCatch(), and then handling the error in the outer function. This does mostly what I want, but doesn't quite give the output that I'd like. The closest I've come is the following:
f <- function(i) {
tryCatch({
check_input(i)
}, error = function(e) stop("in f: ", e$message, call. = FALSE)
)
}
check_input <- function(i) {
if(i < 0)
stop("i is negative, value given was ", i)
}
f(-1)
# Error: in f: i is negative, value given was -1
Ideally, I'd like the error message to be
Error in f: i is negative, value given was -1
, which would be the case if stop were called within f() instead of check_input().
Here's how you can grab the name of the function from the call stack and paste it in to the error message
f <- function(i) {
check_input(i)
}
g <- function(i) {
check_input(i)
}
check_input <- function(i, from=deparse(sys.calls()[[sys.nframe()-1]][[1]])) {
getmsg <- function(m) ifelse(!is.null(from), paste0("in ", from, ": ", m), m)
if(i < 0)
stop(getmsg(paste0("i is negative, value given was ", i)), call. = FALSE)
}
f(-1)
# Error: in f: i is negative, value given was -1
g(-1)
# Error: in g: i is negative, value given was -1
You could also call check_input(i, from="otherfunction") to show whatever function name you want or check_input(i, from=NULL) to suppress the function name.

How to continue function when error is thrown in withCallingHandlers in R

I'm writing a test case for an R function that tests whether an error is being thrown and caught correctly at a certain point in the function and I'm having some trouble getting the test to continue when an error is thrown during execution in withCallingHandlers(...). I'm using this approach:
counter <- 0
withCallingHandlers({
testingFunction(df0, df1)
testingFunction(df2, df3)
testingFunction(df4, df5)
}, warning=function(war){
print(paste(war$message))
}, error=function(err){
print(paste(err$message))
if(err$message == paste("The function should throw this error message",
"at the right time.")){
counter <<- counter + 1
}
})
stopifnot(counter == 2)
The problem I'm running into is that the script is exiting after the first error is (successfully) caught and I'm not sure how to handle the error so that after it's caught, withCallingHandlers simply continues onto the next part of its execution. I understand that it has something to do with a restart object but I'm not sure how to use them correctly. Does anyone know how I could manipulate the above code so that execution of withCallingHandlers(...) continues even when an error is caught?
For a test function
fun1 = function() stop("something specific went wrong")
the idiom
obs = tryCatch(fun1(), error=conditionMessage)
exp = "something specific went wrong"
stopifnot(identical(exp, obs))
is maybe a tidier version of Ryan's, and like his avoids the unfortunate case where an error is thrown but for the wrong reason. The same paradigm works for warnings
fun2 = function(x) as.integer(x)
obs = tryCatch(fun2(c("1", "two")), warning=conditionMessage)
stopifnot(identical("NAs introduced by coercion", obs))
and to check for 'clean' evaluation
obs = tryCatch(fun2(c("1", "2")), warning=conditionMessage,
error=conditionMessage)
stopifnot(identical(1:2, obs))
This is ok, provided Sys.getlocale() is "C" or another encoding that doesn't change the translation of the condition messages.
You can just wrap each call to testingFunction with a call to tryCatch.:
counter <- 0
testForExpectedError <- function(expr) {
tryCatch(expr, error=function(err) {
print(paste(err$message))
if(err$message == paste("The function should throw this error message",
"at the right time.")){
counter <<- counter + 1
}
})
}
testForExpectedError(testingFunction(df0, df1))
testForExpectedError(testingFunction(df2, df3))
testForExpectedError(testingFunction(df4, df5))
stopifnot(counter == 2)

Is there a way to run an expression on.exit() but only if completes normally, not on error?

I'm aware of the function on.exit in R, which is great. It runs the expression when the calling function exits, either normally or as the result of an error.
What I'd like is for the expression only to be run if the calling function returns normally, but not in the case of an error. I have multiple points where the function could return normally, and multiple points where it could fail. Is there a way to do this?
myfunction = function() {
...
on.exit( if (just exited normally without error) <something> )
...
if (...) then return( point 1 )
...
if (...) then return( point 2 )
...
if (...) then return( point 3 )
...
return ( point 4 )
}
The whole point of on.exit() is exactly to be run regardless of the exit status. Hence it disregards any error signal. This is afaik equivalent to the finally statement of the tryCatch function.
If you want to run code only on normal exit, simply put it at the end of your code. Yes, you'll have to restructure it a bit using else statements and by creating only 1 exit point, but that's considered good coding practice by some.
Using your example, that would be:
myfunction = function() {
...
if (...) then out <- point 1
...
else if (...) then out <- point 2
...
else if (...) then out <- point 3
...
else out <- point 4
WhateverNeedsToRunBeforeReturning
return(out)
}
Or see the answer of Charles for a nice implementation of this idea using local().
If you insist on using on.exit(), you can gamble on the working of the traceback mechanism to do something like this :
test <- function(x){
x + 12
}
myFun <- function(y){
on.exit({
err <- if( exists(".Traceback")){
nt <- length(.Traceback)
.Traceback[[nt]] == sys.calls()[[1]]
} else {FALSE}
if(!err) print("test")
})
test(y)
}
.Traceback contains the last call stack resulting in an error. You have to check whether the top call in that stack is equal to the current call, and in that case your call very likely threw the last error. So based on that condition you can try to hack yourself a solution I'd never use myself.
Just wrap the args of all your return function calls with the code that you want done. So your example becomes:
foo = function(thing){do something; return(thing)}
myfunction = function() {
...
if (...) then return( foo(point 1) )
...
if (...) then return( foo(point 2) )
...
if (...) then return( foo(point 3) )
...
return ( foo(point 4) )
}
Or just make each then clause into two statements. Using on.exit to lever some code into a number of places is going to cause spooky action-at-a-distance problems and make the baby Dijkstra cry (read Dijkstra's "GOTO considered harmful" paper).
Bit more readable version of my comment on #Joris' answer:
f = function() {
ret = local({
myvar = 42
if (runif(1) < 0.5)
return(2)
stop('oh noes')
}, environment())
# code to run on success...
print(sprintf('myvar is %d', myvar))
ret
}
I guess there is not a clean way yet. I usually create an OK variable at the beginning as FALSE and turn it to TRUE at the end. I prefer on.exit over isolating all my code into a tryCatch.
myfun = function() {
OK=F # the flag "OK" will be FALSE until the function ends OK
conn = my.db.connection.function()
dbBegin(conn)
on.exit({
if(OK) dbCommit(conn) else dbRollback(conn)
dbDisconnect(conn)
})
# ... Your code. You can edit database as a transaction.
# if anything fails in R or in the database a rollback will occur
OK=T # only if the code came to the end everything went ok, so we set the flag OK as TRUE
return(NULL)
}

Resources