withCallingHandlers()
withCallingHandlers(expr, ..., finally = NULL) any · Added in v2.0.0 · Updated March 25, 2026 · Base Functions 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
| Parameter | Type | Default | Description |
|---|---|---|---|
expr | expression | required | The expression to evaluate with active condition handlers |
... | named handlers | none | Named arguments mapping condition classes to handler functions |
finally | expression | NULL | An 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
| Feature | withCallingHandlers | tryCatch |
|---|---|---|
| Handler type | Calling (non-exiting) | Exiting |
| Access to call stack? | Yes — conditionCall(), sys.call() still work | No — stack unwinds |
| Error recovery? | No — error still terminates after handlers run | Yes — can return a substitute value |
finally argument? | Yes (R 3.0+) | Yes |
| Typical use | Intercept, log, or suppress warnings/messages | Catch-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 textconditionCall(c)— the call that triggered the condition (may beNULLif 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.