15 Errors and conditions
R reports errors with a longjmp: Rf_error() never returns, abandoning your C function on the spot. That has two consequences you must design around. First, any cleanup your function owes — freeing R_Calloc() memory, closing files, restoring global state — will not run unless you arrange it in advance with R_UnwindProtect() or an external pointer finalizer. Second, in C++ the longjmp skips destructors, so RAII objects must live below an R_UnwindProtect() boundary that converts the longjmp into a C++ exception (see R_MakeUnwindCont()).
For catching errors from R code you call, rather than signalling your own, see the protected evaluation entry points in Evaluation.
15.1 Signalling
Follows WRE §6.2, Error signaling closely.
Rf_error() and Rf_warning() take printf-style format strings. If your message is a plain string that might contain %, pass it as Rf_error("%s", msg) so it isn’t interpreted as a format.
To signal an error with a custom class — so R code can catch it selectively with tryCatch(my_class = function(c) ...) — there is no dedicated entry point. Build a condition object (a named list with message and call fields, classed c("my_class", "error", "condition")) and signal it by evaluating a call to stop():
SEXP cls = PROTECT(Rf_allocVector(STRSXP, 3));
SET_STRING_ELT(cls, 0, Rf_mkChar("negative_value"));
SET_STRING_ELT(cls, 1, Rf_mkChar("error"));
SET_STRING_ELT(cls, 2, Rf_mkChar("condition"));
SEXP cond = PROTECT(Rf_mkNamed(VECSXP, (const char *[]){"message", "call", ""}));
SET_VECTOR_ELT(cond, 0, Rf_mkString("x must be non-negative"));
SET_VECTOR_ELT(cond, 1, R_NilValue);
Rf_classgets(cond, cls);
/* Never returns, so the UNPROTECT is never reached */
Rf_eval(Rf_lang2(Rf_install("stop"), cond), R_GlobalEnv);The same pattern with warning() signals a classed warning.
15.1.1 Rf_error(), Rf_errorcall()
throws
Header: Rinternals.h
R equivalent: stop()
Signal an error, optionally including the call in the message.
void Rf_error(const char* format, ...);
void Rf_errorcall(SEXP call, const char* format, ...);Use Rf_errorcall(R_NilValue, ...) to suppress display of the call.
15.1.2 Rf_warning(), Rf_warningcall(), Rf_warningcall_immediate()
throws
Header: R_ext/Error.h
R equivalent: warning()
Signal a warning, optionally including the call or displaying it immediately.
void Rf_warning(const char* format, ...);
void Rf_warningcall(SEXP call, const char*, ...);
void Rf_warningcall_immediate(SEXP call, const char*, ...);15.1.3 error_return(), errorcall_return()
throws
Header: Rinternals.h
Eliminate compiler warnings about non-void functions that don’t return.
#define error_return(msg) { \
Rf_error(msg); \
return R_NilValue; \
}
#define errorcall_return(cl,msg) { \
Rf_errorcall(cl, msg); \
return R_NilValue; \
}Rf_error will longjmp and so any code following will not be executed; however, most compilers do not detect this when providing warnings.
See also: Rf_error()
15.1.4 UNIMPLEMENTED()
throws
Header: R_ext/Error.h
Signal an error for an unimplemented operation.
[[noreturn]] void UNIMPLEMENTED(const char *s);Signals “feature ‘s’ is not implemented”; never returns. Use UNIMPLEMENTED_TYPE() for a type-specific variant.
See also: Rf_error()
15.2 Condition handling and cleanup
Follows WRE §6.13, Condition handling and cleanup code closely.
These functions let C code do what tryCatch() and on.exit() do at the R level: run a body function with a condition handler or cleanup action installed. Reach for R_UnwindProtect() when you need guaranteed cleanup, and the R_tryCatch*() family when you need to inspect or recover from a condition object.
15.2.1 R_UnwindProtect()
needs protect throws
Header: Rinternals.h
Run a C function, guaranteeing a cleanup action runs on normal return and on longjmp.
SEXP R_UnwindProtect(SEXP (*fun)(void *data), void *data,
void (*clean)(void *cdata, Rboolean jump), void *cdata,
SEXP cont);fun: function to run; its return value is passed through.clean: cleanup function, called withjump = FALSEafter a normal return andjump = TRUEbefore a non-local transfer of control resumes.cont: continuation token fromR_MakeUnwindCont(), orR_NilValuefor plain C use.
Returns: The SEXP returned by fun.
This is the primary tool for making C (and C++) code longjmp-safe: free R_Calloc() memory, close files, and restore state in clean. With a continuation token, clean can throw a C++ exception to unwind the C++ stack and then call R_ContinueUnwind() to resume R’s longjmp.
See also: R_MakeUnwindCont(), R_ExecWithCleanup()
15.2.2 R_MakeUnwindCont(), R_ContinueUnwind()
needs protect throws
Header: Rinternals.h
Allocate a continuation token for C++ stack unwinding, and resume the unwind.
SEXP R_MakeUnwindCont(void);
NORET void R_ContinueUnwind(SEXP cont);Returns: R_MakeUnwindCont() returns a SEXP continuation token for use with R_UnwindProtect(); R_ContinueUnwind() never returns.
PROTECT the token before passing it to R_UnwindProtect(). Only needed when C++ code sits between R and the cleanup handler; plain C code should pass R_NilValue as cont instead.
See also: R_UnwindProtect()
15.2.3 R_ExecWithCleanup()
needs protect throws
Header: Rinternals.h
Execute a C function in a protected context, with cleanup before teardown.
SEXP R_ExecWithCleanup(SEXP (*fun)(void *), void *data,
void (*cleanfun)(void *),
void *cleandata);fun: C function to call after context setup. Passed*data.cleanfun: C function to call before context teardown. Passed*data.
Returns: The SEXP returned by fun.
Older, simpler variant of R_UnwindProtect(); the cleanup function is not told whether the exit was a normal return or a longjmp.
See also: R_UnwindProtect()
15.2.4 R_tryCatchError(), R_withCallingErrorHandler()
needs protect throws
Header: Rinternals.h
R equivalent: tryCatch()
Call a C function with a handler installed for R error conditions.
SEXP R_tryCatchError(SEXP (*fun)(void *data), void *data,
SEXP (*hndlr)(SEXP cond, void *hdata), void *hdata);
SEXP R_withCallingErrorHandler(SEXP (*fun)(void *data), void *data,
SEXP (*hndlr)(SEXP cond, void *hdata), void *hdata);hndlr: handler called with the condition object; its return value becomes the result.
Returns: The SEXP returned by fun, or the handler’s return value if an error is signalled.
R_tryCatchError() installs an exiting handler (like tryCatch(error = ...)); R_withCallingErrorHandler() installs a calling handler (like withCallingHandlers(error = ...)) and avoids calling back into R, so it is more efficient. R_tryCatchError() is implemented via R-level tryCatch() and has some overhead.
See also: R_tryCatch(), R_tryEval()
15.2.5 R_tryCatch()
needs protect throws
Header: Rinternals.h
R equivalent: tryCatch()
Call a C function with handlers for arbitrary condition classes and a cleanup action.
SEXP R_tryCatch(SEXP (*fun)(void *data), void *data,
SEXP conds,
SEXP (*hndlr)(SEXP cond, void *hdata), void *hdata,
void (*clean)(void *cdata), void *cdata);conds: condition classes to handle, as a character vector (STRSXP).
Returns: The SEXP returned by fun, or the handler’s return value if a handled condition is signalled.
NULL may be passed for fun or clean if condition handling or cleanup is not needed. Implemented via R-level tryCatch(), so it has some overhead.
See also: R_tryCatchError(), R_UnwindProtect()
15.3 Interrupts
Follows WRE §6.14, Allowing interrupts closely.
15.3.1 R_CheckUserInterrupt()
throws
Header: R_ext/Utils.h
Check for a pending user interrupt, signalling an error if one occurred.
void R_CheckUserInterrupt(void);Call periodically from long-running loops; R cannot interrupt compiled code that never checks. On interrupt it longjmps, so the same cleanup obligations as for Rf_error() apply.
15.3.2 Rf_onintr()
throws
Header: Rinterface.h
R’s default response to a user interrupt.
void Rf_onintr(void);Jumps back to the top level, discarding the current computation. Intended for front-ends and graphics devices; package code should almost always use R_CheckUserInterrupt() instead.
See also: R_CheckUserInterrupt()
15.4 C stack checking
Follows WRE §6.15, C stack checking closely.
15.4.1 R_CheckStack(), R_CheckStack2()
throws
Header: R_ext/Utils.h
Signal an error if the C stack is (nearly) exhausted.
void R_CheckStack(void);
void R_CheckStack2(R_SIZE_T extra);extra:R_CheckStack2()errors when fewer thanextrabytes remain.
Call before deep C recursion; better still, avoid deep recursion or write it tail-recursively so the compiler can optimize it away. Stack checking is not available on all platforms.