rguides

tryCatch

tryCatch(expr, ..., finally)

Introduction

tryCatch() is R’s primary mechanism for handling conditions such as errors, warnings, and messages. It evaluates an expression and routes any raised condition to the appropriate handler function you provide. Without any handlers, tryCatch() simply evaluates expr and returns the result — making it also useful as a mechanism for guaranteeing cleanup via the finally argument.

The function signature is:

tryCatch(expr, ..., finally)
  • expr is the expression to evaluate.
  • ... accepts named handler functions: error, warning, message, and condition.
  • finally is a single expression evaluated regardless of whether a condition was raised.

Handling Errors

The most common use case is catching errors and returning a fallback value. The error handler receives a condition object with at least $message and $call components.

safe_log <- function(x) {
  tryCatch(
    expr = log(x),
    error = function(cnd) {
      message("Error: ", cnd$message)
      NA_real_
    }
  )
}

safe_log(10)
# [1] 2.302585

safe_log("hello")
# Error: non-numeric argument to mathematical function
# [1] NA

The handler function returns the value that tryCatch() will ultimately return. Here, NA_real_ replaces the error, letting the caller proceed without crashing.

The finally Block

finally is evaluated after expr completes (or after a handler returns) and is useful for cleanup tasks like closing file connections or resetting options. Its return value is ignored.

read_first_line <- function(path) {
  conn <- NULL
  tryCatch(
    expr = {
      conn <- file(path, open = "r")
      readLines(conn, n = 1)
    },
    error = function(cnd) NA_character_,
    finally = {
      if (!is.null(conn)) close(conn)
    }
  )
}

# Connection is closed whether readLines() succeeds or fails

finally runs even if the handler itself throws an error. The cleanup happens before that error propagates upward.

Handling Warnings

Warnings are trickier than errors. By default, execution of expr continues after a warning is signalled — the warning handler is called only after expr finishes. If you want to stop on the first warning, set options(warn = 1) beforehand.

result <- tryCatch(
  expr = suppressWarnings(as.numeric(c("1", "2", "three"))),
  warning = function(cnd) {
    message("Warning caught: ", cnd$message)
    NA_real_
  }
)

result
# [1]  1  2 NA

Using suppressWarnings() inside expr is a common pattern when you want to both handle and suppress a warning in one call.

Handler Return Values

When a handler does not explicitly call return(), it returns NULL invisibly. This is easy to miss:

x <- tryCatch(
  expr = stop("oops"),
  error = function(cnd) {
    # no explicit return — returns NULL invisibly
    message("Caught: ", cnd$message)
  }
)

x
# [1] NULL

print(x)
# NULL

Always return a value explicitly from handlers if you need a specific result.

Multiple Handlers

You can supply handlers for different condition types simultaneously. Each handler only fires for its corresponding type.

result <- tryCatch(
  expr = {
    x <- log(-1)    # produces a warning, execution continues
    if (x < 0) stop("Negative value from log")
    x
  },
  warning = function(cnd) {
    message("Warning: ", cnd$message)
    NA_real_
  },
  error = function(cnd) {
    message("Error: ", cnd$message)
    NA_real_
  }
)

# Warning: NaNs produced
# Error: Negative value from log
# [1] NA

The warning fires first (after expr completes), then the subsequent stop() triggers the error handler. Both return NA_real_, so the final result is NA.

Condition Object Structure

Handlers receive a condition object with these key components:

condition <- function(cnd) {
  cnd$message   # character string of the condition message
  cnd$call      # the call that triggered the condition (NULL if call. = FALSE)
  class(cnd)    # e.g. c("error", "condition") or c("warning", "condition")
}

You can inspect the class to branch logic within a generic condition handler, though specific handlers like error and warning are usually clearer.

When tryCatch() Is Not the Right Tool

For simply silencing output, suppressWarnings() and suppressMessages() are shorter and more direct. For re-throwing errors after logging, call stop() inside the error handler. For lower-level control over the call stack, look at withCallingHandlers().

See Also

Summary

tryCatch() wraps an expression and lets you respond to errors, warnings, and messages through handler functions. The finally argument guarantees cleanup runs regardless of what happens. Handlers receive condition objects you can inspect for the message text, call, and condition class. When a handler returns a value, that becomes tryCatch()’s return value — unless the handler itself throws, in which case finally still runs first. For simple suppression, use suppressWarnings() or suppressMessages() instead.