Skip to content

Error handling

Exception hierarchy

RBridgeError              base class for all r_bridge exceptions
├── RStartupError         R process failed to start or timed out during startup
├── RTimeoutError         a call did not complete within the allowed timeout
├── RError                an error was raised on the R side
└── RProtocolError        R sent a malformed response envelope

All exceptions are importable from r_bridge.exceptions or directly from r_bridge.

R-side errors

When R calls stop() or an unhandled error occurs, r_bridge raises RError.

from r_bridge import RBridge
from r_bridge.exceptions import RError

with RBridge() as r:
    try:
        r.eval("stop('something went wrong')")
    except RError as e:
        print(e.message)    # "something went wrong"
        print(e.call)       # R call that triggered the error (or None)
        print(e.traceback)  # list of traceback strings from R
        print(e.warnings)   # list of warnings captured before the error
        print(e.stderr)     # accumulated R stderr at the time of the error

The bridge stays alive after an RError. You can continue making calls.

Timeouts

from r_bridge.exceptions import RTimeoutError

# Bridge-wide timeout (applies to all calls)
with RBridge(call_timeout=10.0) as r:
    ...

# Per-call timeout override
with RBridge() as r:
    try:
        r.eval("Sys.sleep(99)", timeout=1.0)
    except RTimeoutError:
        print("R took too long")

Warning

After a RTimeoutError the bridge is marked dead and cannot be reused. Create a new RBridge instance to recover.

Startup errors

from r_bridge.exceptions import RStartupError

try:
    with RBridge(r_executable="/wrong/path/Rscript") as r:
        ...
except RStartupError as e:
    print(e)   # includes R stderr output to help diagnose the problem

R warnings

R warnings are captured and muffled — they never appear as unhandled output. After a successful call they are returned alongside the result and can be inspected from the exception on error:

import math

with RBridge() as r:
    val = r.log(-1.0)      # produces NaN + a warning in R
    print(math.isnan(val)) # True — the call succeeded despite the warning

Verbose mode

verbose=True is the easiest way to see what is happening in real time:

with RBridge(verbose=True) as r:
    r.x = [1, 2, 3]
    r.mean(r.x)

All output goes to sys.stderr:

[R set]    x = {'__type__': 'integer_vector', 'value': [1, 2, 3]}
[R call]   mean([...])
[R stdout] ...    ← from cat() in R
[R stderr] ...    ← from message() / warnings in R
Prefix Source
[R call] call_func operation
[R eval] eval_expr operation
[R exec] exec_script operation (first line of script shown)
[R set] set_var operation
[R get] get_var operation
[R stdout] non-protocol R stdout (e.g. cat())
[R stderr] R stderr (e.g. message(), warnings)