R Debugging

Debugging is the process of finding and fixing errors in your code. R provides a set of interactive tools that let you pause execution, inspect variables, step through code line by line, and trace exactly where things go wrong. Knowing these tools cuts debugging time from hours to minutes.

Types of Errors in R

Type         Example                    How It Appears
──────────────────────────────────────────────────────────────────
Syntax       missing ), extra {         Error before code runs
Runtime      divide by zero, wrong type Error during execution
Logic        wrong formula, wrong index Code runs, wrong answer
Warning      negative sqrt, NA coercion Runs but alerts you

Step 1: Read the Error Message

result <- mean(c(1, 2, "three"))
# Warning: NAs introduced by coercion
# [1] NA

my_list <- list(a=1, b=2)
my_list$c + 1
# Error in my_list$c + 1 : non-numeric argument

# R tells you:
# what went wrong (non-numeric argument)
# where it went wrong (my_list$c + 1)

print() and cat() — Quick Inspection

compute_discount <- function(price, rate) {
  cat("DEBUG price:", price, "rate:", rate, "\n")  # print inputs
  discount <- price * rate
  cat("DEBUG discount:", discount, "\n")            # print intermediate
  final <- price - discount
  return(final)
}

compute_discount(1000, 0.15)
# DEBUG price: 1000 rate: 0.15
# DEBUG discount: 150
# [1] 850

browser() — Interactive Breakpoint

analyze <- function(data) {
  cleaned <- na.omit(data)
  browser()              # execution PAUSES here
  result <- mean(cleaned)
  return(result)
}

# When browser() pauses, you are in an interactive session:
# n   → execute next line
# s   → step INTO a function
# c   → continue to next breakpoint
# Q   → quit debugger
# ls()           → see local variables
# print(cleaned) → inspect any variable

debug() — Step Through an Entire Function

my_func <- function(x, y) {
  a <- x + y
  b <- a * 2
  return(b)
}

debug(my_func)      # activate step-through
my_func(3, 4)       # opens debugger — step through each line

undebug(my_func)    # deactivate

debugonce() — Debug One Call Only

debugonce(my_func)   # only debugs on the very next call
my_func(5, 6)        # debugger opens
my_func(7, 8)        # runs normally (debugger is off)

traceback() — Find Where an Error Occurred

f3 <- function() stop("Something broke")
f2 <- function() f3()
f1 <- function() f2()

f1()          # Error in f3(): Something broke
traceback()
# 3: f3() at #1
# 2: f2() at #1
# 1: f1()

# traceback shows the call stack — read bottom-up to find root cause

tracebacks in RStudio

In RStudio, after an error, click the Show Traceback button that appears in the console. It shows the full call stack visually. Under Debug → On Error → Break in Code, RStudio drops you into the debugger automatically on every error.

options(error=recover) — Post-Mortem Debugging

options(error=recover)   # activate
f1()    # when error occurs, shows call stack; type a number to enter that frame

# Inside a frame: inspect local variables, test expressions
# Type Q to exit

options(error=NULL)   # deactivate when done

Checking Inputs Early

# Validate function inputs at the top → errors are clear and early
safe_divide <- function(x, y) {
  stopifnot(is.numeric(x), is.numeric(y))   # error if FALSE
  if (y == 0) stop("Cannot divide by zero")
  x / y
}

safe_divide(10, 0)      # Error: Cannot divide by zero
safe_divide("a", 2)     # Error: is.numeric(x) is not TRUE

Debugging Checklist

1. Read the error message in full
2. Run traceback() to find the source
3. Add print()/cat() around the suspect code
4. Use browser() to pause and inspect at the exact line
5. Check inputs — wrong type is the most common cause
6. Simplify — test with the smallest possible input
7. Check NA values — they propagate silently and cause logic errors

Debugging is a skill that improves with practice. The best R programmers are not those who write bug-free code on the first attempt — they are those who find and fix bugs quickly. Make browser() and traceback() part of your daily toolkit from day one.

Leave a Comment

Your email address will not be published. Required fields are marked *