Tasks

1. Identify The Bug

Knowing you have a bug is the first step.

If you have an error message, this step is taken care of for you:

x = c(1, 39, 2982, '5', 22)

sqrt(x)
Error in sqrt(x): non-numeric argument to mathematical function

However, many times there will be no error messages, you just have to figure out that something isn’t right.

range(x)
[1] "1" "5"

Strategies

Develop expectations about what your data should look like and check them frequently, not just at the end of your process. Use investigative functions to check your expectations.

Investigative functions

  • print()
  • head()
  • str()
  • View()
  • dim()
  • range()
  • table()
  • class()
  • is.na()

Unit Tests

Unit tests are outside the scope of this workshop but you can find more information via the testthat package.

Common Problems

  • Typos/syntax errors
  • Object is not the class that you think it is
  • Column is not the type that you think it is
  • File is not in the place that you think it is
  • Columns missing from data
  • Missing values (NAs) in the data
  • Reused variable names
  • Mutually exclusive filtering criteria

2. Locate the Bug

Start debugging with an empty environment. This means you have restarted R, and haven’t automatically loaded any data or restored your workspace using an .RData file. You may need to uncheck an option in your global options menu.

Run your script interactively in the console. This will help identify the line of code where any errors occur. If your bug is not accompanied by an error message, use investigative functions at each step in your script to figure at what step the problem originates.

range(x)
[1] "1" "5"
str(x)
 chr [1:5] "1" "39" "2982" "5" "22"

In this case all of our values are strings, so R is sorting them as if they were words, not numbers.

Debugging Inside Functions

If the bug is happening inside of a function, you have several options to troubleshoot. If you wrote the function, you can add the function call browser() inside your function. browser() opens an interactive debugging environment when called, allowing you to investigate what objects exist in the local environment of your function. It also means you can run the lines of the code inside your function interactively. If you did not write the offending function, you can use debug() to insert browser() as the first line of code of the function in question. Use undebug() to remove the
browser() function call when you are done.

For bugs where the problem is nested somewhere deep in a function that you may or may not have access to, you can use the function recover() to enter a debugging session deep in the function call rabbit hole. By setting

options(error=recover)

you will trigger recover() to run any time you hit an error. This will then allow you to select the evaluation environment level at which to run a debugging session (see below).

Non-interactive Debugging

When running knitting/rendering notebooks, Rmarkdown and quarto notebooks provide the line numbers of the entire code chunk where the error occurred instead of the exact line number of the error. If you are struggling to identify where in a notebook an error occurs and running code in the console does not trigger the error, break your longer code chunks up into shorter ones. This will narrow down the number of lines of code you need to investigate.

If you don’t have any ability work with R interactively, like in the case of a remote computing cluster, you can use the function dump.frames() to create an R object called last.dump that contains information about the evaluation environment in question. In lieu of creating an R object, you can write that information to a file as well. You can even set options=dump.frames if you want environment information every time you hit an error.

3. Investigate the Bug

Sometimes simply locating the bug is enough to figure out how to solve it, like in the case of syntax errors. However, many times locating the bug is just the beginning…

When identifying the location of the bug is not enough to figure out how to fix it, it’s time to go looking for help.

  • Built-in R documentation via ? or help()
  • RDocumentation.org
  • The CRAN page or Github repository for a specific package
  • Google
  • Rseek.org, like google but only for R related info. Can be helpful if you are getting a lot of results on Google from other programming languages

Tips for googling:

  • Copy/paste error messages
  • Include “R” and names of any packages you are using
  • Specify the function you think may be causing the problem
  • Mention the data type/class you are working with

4. Reproduce the Bug

Sometimes though, Google doesn’t doesn’t even know what you are talking about. In this case, your best option is to get proactive and ask for help. You can do this through any number of forums, including but not limited to:

Whenever you ask for help, important that you provide people all the information they need to understand the problem, but not so much information that that determining the problem becomes a slog. Enter the Reprex.

When asking your question make sure you:

  • Have done your homework and exhausted your options from Step 3 first
  • Use a clear and concise title
  • Describe your goal, what you expected to happen, and what actually happened
  • Copy/paste output from sessionInfo() into your post
  • Include a reprex

Reprexes

Repr(oducible) ex(amples), are minimal of code that trigger your bug and can be run by anyone, without any specialized data or software. Many times, the act of creating a reprex will help you debug your code.

Remember to:

  • Create the reprex in a separate script
  • List all packages loaded in your environment
  • Simulate data, use builtin data or provide an easily accessible small subset of your data (no csvs)
  • Remove all extraneous packages and code
  • Clear your environment/restart R before testing your reprex
  • Test your reprex to make sure it triggers the error
  • No Screenshots!

For more detailed guidance on asking good questions see the R Posting Guide. For tools to craft your reprex, there is a tidyverse package with the same name: reprex

5. Fix the Bug?

Sometimes fixing the bug is trivial once you have determined the cause. Other times, there is more work to do.

  • try() and tryCatch()
  • Write your own functions that avoid the issue
  • Report the bug
    • packageDescription() to find bug report location
    • often times this is done by creating an issue on Github
    • Make sure that the problem is actually a bug and not just a behavior you don’t like

For more information on reporting bugs in R see the Reporting Bugs in R page on CRAN.

6. Pevent the Bug

  • try() and tryCatch()
  • Document, document, document!
  • Write your own error messages using stop() or warnings using warning()
  • Follow up on any posts you made with the solution that actually worked