Reading — step 1 of 5
Learn
R has multiple error mechanisms. Knowing them differentiates production code from notebooks.
Throw an error:
stop("something broke")
stop("x must be positive, got: ", x)
Throw a warning (non-fatal):
warning("deprecated, use new_function() instead")
Send a message (information, not warning):
message("loaded 1000 rows")
Catch with tryCatch:
result <- tryCatch({
risky_operation()
}, error = function(e) {
cat("caught:", conditionMessage(e), "\n")
NA # return value on error
}, warning = function(w) {
cat("warning:", conditionMessage(w), "\n")
-1
}, finally = {
cat("cleanup\n")
})
The finally block runs whether or not error occurred. tryCatch is R's try/catch.
try() — older, simpler. Returns an "try-error" object on failure:
result <- try(risky(), silent = TRUE)
if (inherits(result, "try-error")) {
cat("failed\n")
}
withCallingHandlers — like tryCatch but returns control to the throwing context (for warnings, you can keep going):
result <- withCallingHandlers({
risky()
}, warning = function(w) {
log_warning(w)
invokeRestart("muffleWarning") # suppress and continue
})
Custom condition classes for structured errors:
stop_validation <- function(msg) {
structure(
class = c("validation_error", "error", "condition"),
list(message = msg, call = sys.call(-1))
) |> stop()
}
tryCatch({
stop_validation("age must be positive")
}, validation_error = function(e) {
cat("validation failed:", conditionMessage(e), "\n")
})
stopifnot() for invariants:
stopifnot(
is.numeric(x),
length(x) > 0,
all(x >= 0)
)
If any condition fails, throws an error naming the failing one. Used heavily inside R itself.
assertthat package for richer messages:
library(assertthat)
assert_that(is.numeric(x), msg = "x must be numeric")
browser() for interactive debugging:
my_fn <- function(x) {
browser() # drops into interactive shell here
x * 2
}
When you call my_fn(5), R pauses and gives you a debug REPL where you can inspect variables, step, continue.
Best practices:
- Use
stop()for things callers can't recover from (bug, missing data) - Use
warning()for unusual situations callers should know about - Validate inputs at function start (
stopifnot) - Custom condition classes for libraries — let users catch specific errors
- Test error paths! Use
expect_error()intestthat
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…