⇦ Back

Fail Safely

If there’s an error in your R code, your script will fail. It will run up to the point where the bug exists and then exit, possibly giving you an error message which may or may not be useful in debugging the problem. This is fine if you’re still working on your script or if it’s not being used for anything important, but if it’s ‘production ready’ and being used for mission critical analysis then you’ve got yourself a problem! Additionally, if your coding project is very large and spans many files and databases it can become very hard to track down the exact problem and debug it efficiently. For these reasons (and others) R gives you the power to customise what happens if a particular section of code produces a warning or an error. This is known as the “try-catch” technique: you try to run a piece of code and catch any errors that are created.

The code itself is fairly self-explanatory. The function that implements a try-catch is called tryCatch() and there are four sections to it:

  1. The code you want to try run
  2. What you want to happen if this code throws a warning
  3. What you want to happen if this code throws an error
  4. Additional code that will run regardless of whether there was an error or not

The first part is compulsory, the last three are optional. Here’s a basic example:

tryCatch({
    print(
        "This is the 'try' part. The script will try to run the code in here"
    )},
    warning = function(w) {
        print("Warning! Something went wrong but I can continue")
    },
    error = function(e) {
        print("Whoops! Something went so wrong I can't continue")
        stop()
    },
    finally = {
        print("This text will print regardless of what happened")
    }
)
## [1] "This is the 'try' part. The script will try to run the code in here"
## [1] "This text will print regardless of what happened"

The script tried to run the first print statement and succeeded. It then bypassed the ‘warning’ function and the ‘error’ function as no warning or error was produced, but it did print the ‘finally’ function as that gets run regardless.

An Example

A useful implementation of this is when you are working with data that someone else has given you or that has been input by a user. You can’t guarantee that the data is going to be in the right format. Here’s an example where the users of an app input their age and a script uses that to estimate their birth year:

user_input <- c(21, 22, 23, 24)
current_year <- as.numeric(format(Sys.Date(), "%Y"))
print(current_year - user_input)
## [1] 2000 1999 1998 1997

What would happen if one of the ages was in the string format by accident? It would cause the script to crash and the entire app might then go offline. This could be handled by doing the following:

user_input <- c(21, 22, "23", 24)
current_year <- as.numeric(format(Sys.Date(), "%Y"))
tryCatch({
        print(current_year - user_input)
    },
    error = function(e) {
        print("Whoops! An error occurred but I can continue anyway!")
        print(current_year - as.numeric(user_input))
    }
)
## [1] "Whoops! An error occurred but I can continue anyway!"
## [1] 2000 1999 1998 1997

…and you can sleep easily knowing your code can handle exceptions!

⇦ Back