Skip to main content

error

Macro error 

Source
macro_rules! error {
    (class = $class:expr, data = $data:tt, $($arg:tt)*) => { ... };
    (data = $data:tt, $($arg:tt)*) => { ... };
    (class = $class:expr, $($arg:tt)*) => { ... };
    ($($arg:tt)*) => { ... };
}
Expand description

Raise an R error from Rust with rust_error class layering.

Rides the tagged-condition transport that every #[miniextendr] function uses. The raised condition has class c("rust_error", "simpleError", "error", "condition").

An optional class = "name" form prepends a custom class for programmatic catching: c("name", "rust_error", "simpleError", "error", "condition").

§Structured data = ... payloads

An optional data = ... form (after class, before the message) attaches named fields to the condition object, rlang-abort()-style. Handlers read them as e$<name> instead of parsing the message string:

// Single field:
mx::error!(class = "range_error", data = ("value", value), "value {value} out of range");

// Multiple fields (bracketed list of pairs):
mx::error!(
    class = "validation_error",
    data = [("value", value), ("min", 0), ("max", 100)],
    "value {value} out of range"
);

// Keyed builder sugar (bare-ident keys, stringified by the macro):
mx::error!(
    class = "validation_error",
    data = { value = value, min = 0, max = 100 },
    "value {value} out of range"
);
tryCatch(validate(150L), validation_error = function(e) c(e$value, e$min, e$max))
# [1] 150   0 100

Argument order is fixed: class = ... (optional), then data = ... (optional), then the format message.

Supported value types: scalars and Vecs of i32, f64, bool, and String (plus &str / Vec<&str>, converted to owned); their NA-aware Option / Vec<Option<_>> forms (→ R NA); the wide-integer ladder (i64 / u32); and the RValue::debug escape hatch for any T: Debug. The payload must be Send — it travels through panic_any and may cross the worker→main thread boundary, so live SEXPs cannot ride along; the R objects are materialised on the main thread at the unwind boundary. For nested lists or complex/raw values build an RValue directly.

§See also

  • crate::warning! / crate::message! / crate::condition! — the non-error sibling kinds (warning continues execution; message is muffled by suppressMessages; condition is silent without a handler).
  • std::panic! — escape hatch with the same rust_error class layering but no custom-class slot. Use for true bugs / impossible states; reach for error! when callers might want to route by class.
  • AsRError — wraps Result<_, E: std::error::Error> for value-style propagation through Rust code; converts at the boundary.
  • crate::error_value — module-level rationale for the tagged-SEXP transport and the error_in_r default.

Name-collision note. Because pub mod error exists at the crate root, use miniextendr_api::error imports the module rather than this macro. Invoke via miniextendr_api::error!(...) (fully qualified) or via mx::error!(...) after use miniextendr_api as mx;.

§Examples

use miniextendr_api as mx;

#[miniextendr]
fn fail() {
    mx::error!("something went wrong: {}", 42);
}

// With a custom class for tryCatch:
#[miniextendr]
fn typed_fail(name: &str) {
    mx::error!(class = "my_error", "missing field: {name}");
}
tryCatch(fail(), rust_error = function(e) conditionMessage(e))
# [1] "something went wrong: 42"

tryCatch(typed_fail("x"), my_error = function(e) "caught!")
# [1] "caught!"