withCallingHandlers()

withCallingHandlers(expr, ..., finally = NULL)
Returns: any · Added in v2.0.0 · Updated March 25, 2026 · Base Functions
r conditions error-handling warnings base

withCallingHandlers() registers calling handlers for R conditions such as warnings, messages, errors, and interrupts. It evaluates an expression while intercepting any conditions that occur, running your handler functions from within the signalling function’s context rather than after it has returned.

The key distinction from tryCatch() is that calling handlers do not exit. Execution continues within the same context after the handler runs, and the call stack stays intact — sys.call(), sys.frame(), and conditionCall() all remain accessible inside your handler. This makes withCallingHandlers() useful when you need to inspect, log, or suppress conditions without interrupting the flow of a computation.

Syntax

withCallingHandlers(expr, ..., finally = NULL)

Parameters

ParameterTypeDefaultDescription
exprexpressionrequiredThe expression to evaluate with active condition handlers
...named handlersnoneNamed arguments mapping condition classes to handler functions
finallyexpressionNULLAn expression evaluated on exit, whether normal or via condition (R 3.0+)

Each handler function must accept a single argument — the condition object. Common condition classes you can handle: warning, message, error, interrupt, or any custom class created with signalCondition().

Return Value

withCallingHandlers() returns the value of expr if execution completes without an error. If an error is signalled and handled, the handlers run but execution still terminates. Unlike tryCatch(), withCallingHandlers() cannot suppress an error or return a substitute value.

withCallingHandlers vs tryCatch

FeaturewithCallingHandlerstryCatch
Handler typeCalling (non-exiting)Exiting
Access to call stack?Yes — conditionCall(), sys.call() still workNo — stack unwinds
Error recovery?No — error still terminates after handlers runYes — can return a substitute value
finally argument?Yes (R 3.0+)Yes
Typical useIntercept, log, or suppress warnings/messagesCatch-and-recover from errors

Use withCallingHandlers when you need to observe conditions without stopping execution. Use tryCatch when you need to handle an error and continue with a fallback value.

Condition Handler Functions

Inside a handler function, several accessors extract information from the condition object:

  • conditionMessage(c) — the message text
  • conditionCall(c) — the call that triggered the condition (may be NULL if no call context)
  • as.character(c) — converts the condition to a string

To suppress a warning or message from within a handler, call invokeRestart("muffleWarning") or invokeRestart("muffleMessage") respectively.

Examples

Intercepting and logging a warning

result <- withCallingHandlers(
  {
    x <- c(1, 2, NA, 4)
    mean(x)
  },
  warning = function(c) {
    cat("Warning caught:", conditionMessage(c), "\n")
    cat("From call:", deparse(conditionCall(c)), "\n")
    invokeRestart("muffleWarning")
  }
)
# Warning caught: In mean.default(x) : NAs introduced by coercion
# From call: mean.default(x)
# [1] 2.333333

The handler receives the condition object, logs where the warning originated, and muffles it so it does not reach the user. The function still returns the result of mean(x).

Suppressing messages

result <- withCallingHandlers(
  {
    message("Loading data...")
    "dataset loaded"
  },
  message = function(c) {
    cat("Muffling message:", conditionMessage(c), "\n")
    invokeRestart("muffleMessage")
  }
)
# Muffling message: Loading data...
# [1] "dataset loaded"

Inspecting errors (cannot recover)

result <- withCallingHandlers(
  {
    stop("something went wrong")
  },
  error = function(c) {
    cat("Caught error:", conditionMessage(c), "\n")
    cat("Call was:", deparse(conditionCall(c)), "\n")
  }
)
# Caught error: something went wrong
# Call was: stop("something went wrong")
# Error: something went wrong

The error handler runs, but execution still terminates afterwards. The assignment to result never completes because withCallingHandlers() cannot recover from errors. Use tryCatch if you need to handle an error and continue.

Using finally for cleanup

conn <- NULL
result <- withCallingHandlers(
  {
    conn <- file("temp.txt", open = "w")
    writeLines("hello", conn)
    "success"
  },
  warning = function(c) {
    cat("Warning during write:", conditionMessage(c), "\n")
    invokeRestart("muffleWarning")
  },
  finally = {
    if (!is.null(conn)) close(conn)
  }
)
# [1] "success"

The finally block runs whether the expression completes normally or a condition is raised. This makes it useful for cleanup tasks like closing connections or removing temporary files.

Common Pitfalls

Handler functions should not re-signal the same condition class. If your warning handler calls warning() again, the new warning’s handler search begins from the parent frame of the current handler. This can lead to confusing control flow or infinite loops.

conditionCall(c) may be NULL. If a condition is signalled without an associated call — for example, stop("some message") at the top level with no function wrapper — then conditionCall(c) returns NULL. Always check before passing it to deparse() or similar functions.

Errors are not suppressed. Unlike tryCatch(), calling handlers cannot return a substitute value after an error. The error still terminates execution after your handlers run.

finally evaluation context. The finally expression is evaluated in the environment where withCallingHandlers() was called, but after all handlers have finished.

See Also

  • cat() — output objects to the console
  • is.na() — test for missing values, often used alongside condition handling
  • mean() — a common source of NA warnings in data analysis