Signal structured errors with metadata, timestamps, and backtraces
Source:R/general_stop_ctx.R
stop_ctx.Rd
Signals errors with rich context, wrapping rlang::abort()
. It includes:
The calling function name (if applicable).
User-defined metadata (e.g., vectors, lists, data frames, tibbles, SpatRaster, RasterLayer, RasterStack, RasterBrick, sf objects, regression models, ggplot objects, S4 objects).
Optional timestamps/dates.
Optional backtraces to aid debugging.
Usage
stop_ctx(
message,
...,
class = NULL,
call = NULL,
parent = NULL,
include_backtrace = FALSE,
cat_timestamp = TRUE,
cat_date = FALSE
)
Arguments
- message
Character. The primary error message to display.
- ...
Named R objects to include as metadata. These can be of various types, such as vectors, lists, data frames, tibbles, SpatRaster, RasterLayer, RasterStack, RasterBrick, sf objects, regression models (e.g., lm, glm), ggplot objects, S4 objects, and more. Unnamed arguments will cause an error due to
.named = TRUE
inrlang::enquos()
.NULL
values are displayed as "NULL".- class
Character or
NULL.
Subclass(es) for the error condition. Defaults toNULL
. See rlang::abort for more details.- call
Call or
NULL
. The call causing the error. Defaults to the caller's expression. See rlang::abort for more details.- parent
Condition or
NULL
. Parent error for nesting. Defaults toNULL
. See rlang::abort for more details.- include_backtrace
Logical. If
TRUE
, includes a compact backtrace. Default:FALSE
.- cat_timestamp
Logical. If
TRUE
, prepends a timestamp (HH:MM:SS). Default:TRUE
.- cat_date
Logical. If
TRUE
, prepends the date (YYYY-MM-DD). Default:FALSE
.
Value
Does not return; throws an error via rlang::abort()
.
Metadata Output
The metadata section in the error message displays each provided object with its name, the verbatim expression used, its class, and its value:
Object Name: The name of the argument (e.g.,
file
).Verbatim Expression: The expression passed (e.g.,
"data.csv"
).Class: The class of the object, with multiple classes concatenated using
+
(e.g.,<tbl_df + tbl + data.frame>
).Value: The formatted output of the object, using methods like
print()
,summary()
,glimpse()
, orstr()
, depending on the object type.
For example:
----- Metadata -----
file ["data.csv"]: <character>
"data.csv"
type ["missing_input"]: <character>
"missing_input"
Complex objects, such as data frames or raster layers, will display their structure or summary as appropriate.
Examples
# loading packages
load_packages(dplyr, sf, terra, raster)
# -------------------------------------------------------------------
# Basic error with metadata and backtrace
try(
stop_ctx(
message = "File not found", file = "data.csv",
type = "missing_input", foo = 1:3, include_backtrace = TRUE))
#> Error in try(stop_ctx(message = "File not found", file = "data.csv", type = "missing_input", :
#> File not found - 15:32:58
#>
#> ----- Metadata -----
#>
#> file ["data.csv"]: <character>
#> data.csv
#>
#> type ["missing_input"]: <character>
#> missing_input
#>
#> foo [1:3]: <integer>
#> 1, 2, 3
#>
#> ----- Backtrace -----
#> 1. └─pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
#> 2. └─pkgdown::build_site(...)
#> 3. └─pkgdown:::build_site_local(...)
#> 4. └─pkgdown::build_reference(...)
#> 5. ├─pkgdown:::unwrap_purrr_error(...)
#> 6. │ └─base::withCallingHandlers(...)
#> 7. └─purrr::map(...)
#> 8. └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#> 9. ├─purrr:::with_indexed_errors(...)
#> 10. │ └─base::withCallingHandlers(...)
#> 11. ├─purrr:::call_with_cleanup(...)
#> 12. └─pkgdown (local) .f(.x[[i]], ...)
#> 13. ├─base::withCallingHandlers(...)
#> 14. └─pkgdown:::data_reference_topic(...)
#> 15. └─pkgdown:::run_examples(...)
#> 16. └─pkgdown:::highlight_examples(code, topic, env = env)
#> 17. └─downlit::evaluate_and_highlight(...)
#> 18. └─evaluate::evaluate(code, child_env(env), new_device = TRUE, output_handler = output_handler)
#> 19. ├─base::withRestarts(...)
#> 20. │ └─base (local) withRestartList(expr, restarts)
#> 21. │ ├─base (local) withOneRestart(withRestartList(expr, restarts[-nr]), restarts[[nr]])
#> 22. │ │ └─base (local) doWithOneRestart(return(expr), restart)
#> 23. │ └─base (local) withRestartList(expr, restarts[-nr])
#> 24. │ └─base (local) withOneRestart(expr, restarts[[1L]])
#> 25. │ └─base (local) doWithOneRestart(return(expr), restart)
#> 26. ├─evaluate:::with_handlers(...)
#> 27. │ ├─base::eval(call)
#> 28. │ │ └─base::eval(call)
#> 29. │ └─base::withCallingHandlers(...)
#> 30. ├─base::withVisible(eval(expr, envir))
#> 31. └─base::eval(expr, envir)
#> 32. └─base::eval(expr, envir)
# -------------------------------------------------------------------
# Include date in error message; no backtrace
try(
stop_ctx(
message = "File not found", file = "data.csv",
type = "missing_input", cat_date = TRUE))
#> Error in try(stop_ctx(message = "File not found", file = "data.csv", type = "missing_input", :
#> File not found - 23/07/2025 15:32:58
#>
#> ----- Metadata -----
#>
#> file ["data.csv"]: <character>
#> data.csv
#>
#> type ["missing_input"]: <character>
#> missing_input
# -------------------------------------------------------------------
# Complex objects as metadata
terra_obj <- terra::rast()
raster_obj <- raster::raster()
sf_obj <- sf::st_point(c(0,0))
lm_obj <- lm(mpg ~ wt, data = mtcars)
try(
stop_ctx(
message = "File not found", raster = raster_obj, terra = terra_obj,
data_frame = iris, matrix = as.matrix(iris), sf_obj = sf_obj,
lm_obj = lm_obj))
#> Error in try(stop_ctx(message = "File not found", raster = raster_obj, :
#> File not found - 15:32:58
#>
#> ----- Metadata -----
#>
#> raster [raster_obj]: <RasterLayer>
#> class : RasterLayer
#> dimensions : 180, 360, 64800 (nrow, ncol, ncell)
#> resolution : 1, 1 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> crs : +proj=longlat +datum=WGS84 +no_defs
#>
#> terra [terra_obj]: <SpatRaster>
#> class : SpatRaster
#> size : 180, 360, 1 (nrow, ncol, nlyr)
#> resolution : 1, 1 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#>
#> data_frame [iris]: <data.frame>
#> Rows: 150
#> Columns: 5
#> $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
#> $ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
#> $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
#> $ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
#>
#> matrix [as.matrix(iris)]: <matrix + array>
#> chr [1:150, 1:5] "5.1" "4.9" "4.7" "4.6" "5.0" "5.4" "4.6" "5.0" "4.4" ...
#> - attr(*, "dimnames")=List of 2
#> ..$ : NULL
#> ..$ : chr [1:5] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" ...
#>
#> sf_obj [sf_obj]: <XY + POINT + sfg>
#> 0, 0
#>
#> lm_obj [lm_obj]: <lm>
#> Call:
#> lm(formula = mpg ~ wt, data = mtcars)
#> Coefficients:
#> (Intercept) wt
#> 37.285 -5.344
# -------------------------------------------------------------------
# S4 object as metadata
setClass("Student", slots = list(name = "character", age = "numeric"))
student <- new("Student", name = "John Doe", age = 23)
try(
stop_ctx(
message = "Student record error",
metadata = student, type = "invalid_data", include_backtrace = FALSE))
#> Error in try(stop_ctx(message = "Student record error", metadata = student, :
#> Student record error - 15:32:58
#>
#> ----- Metadata -----
#>
#> metadata [student]: <Student>
#> Length Class Mode
#> 1 Student S4
#>
#> type ["invalid_data"]: <character>
#> invalid_data
# -------------------------------------------------------------------
# Nested function error with backtrace
f3 <- function(x) {
stop_ctx("Non-numeric input in f3()", input = x, include_backtrace = TRUE)
}
f2 <- function(y) f3(y + 1)
f1 <- function(z) f2(z * 3)
# Output includes: "Calling Function: f1" before metadata
try(f1("not a number"))
#> Error in value[[3L]](cond) :
#> Error evaluating argument 'input': non-numeric argument to binary operator - 15:32:58
#>
#> ----- Backtrace -----
#> 1. └─pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
#> 2. └─pkgdown::build_site(...)
#> 3. └─pkgdown:::build_site_local(...)
#> 4. └─pkgdown::build_reference(...)
#> 5. ├─pkgdown:::unwrap_purrr_error(...)
#> 6. │ └─base::withCallingHandlers(...)
#> 7. └─purrr::map(...)
#> 8. └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#> 9. ├─purrr:::with_indexed_errors(...)
#> 10. │ └─base::withCallingHandlers(...)
#> 11. ├─purrr:::call_with_cleanup(...)
#> 12. └─pkgdown (local) .f(.x[[i]], ...)
#> 13. ├─base::withCallingHandlers(...)
#> 14. └─pkgdown:::data_reference_topic(...)
#> 15. └─pkgdown:::run_examples(...)
#> 16. └─pkgdown:::highlight_examples(code, topic, env = env)
#> 17. └─downlit::evaluate_and_highlight(...)
#> 18. └─evaluate::evaluate(code, child_env(env), new_device = TRUE, output_handler = output_handler)
#> 19. ├─base::withRestarts(...)
#> 20. │ └─base (local) withRestartList(expr, restarts)
#> 21. │ ├─base (local) withOneRestart(withRestartList(expr, restarts[-nr]), restarts[[nr]])
#> 22. │ │ └─base (local) doWithOneRestart(return(expr), restart)
#> 23. │ └─base (local) withRestartList(expr, restarts[-nr])
#> 24. │ └─base (local) withOneRestart(expr, restarts[[1L]])
#> 25. │ └─base (local) doWithOneRestart(return(expr), restart)
#> 26. ├─evaluate:::with_handlers(...)
#> 27. │ ├─base::eval(call)
#> 28. │ │ └─base::eval(call)
#> 29. │ └─base::withCallingHandlers(...)
#> 30. ├─base::withVisible(eval(expr, envir))
#> 31. └─base::eval(expr, envir)
#> 32. └─base::eval(expr, envir)
#> 33. ├─base::try(f1("not a number"))
#> 34. │ └─base::tryCatch(...)
#> 35. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 36. │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 37. │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 38. └─f1("not a number")
#> 39. └─f2(z * 3)
#> 40. └─f3(y + 1)
#> 41. └─ecokit::stop_ctx("Non-numeric input in f3()", input = x, include_backtrace = TRUE)
#> 42. └─base::tryCatch(...)
#> 43. └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 44. └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 45. └─value[[3L]](cond)
#> Caused by error in `z * 3`:
#> ! non-numeric argument to binary operator
# -------------------------------------------------------------------
# Nested function error without metadata
f3 <- function() {
stop_ctx(message = "Error in f3()", include_backtrace = TRUE)
}
f2 <- function(y) f3()
f1 <- function(z) f2()
# Output includes: "Calling Function: f1" before metadata
try(f1())
#> Error in f3() : Error in f3() - 15:32:58
#>
#> ----- Backtrace -----
#> 1. └─pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
#> 2. └─pkgdown::build_site(...)
#> 3. └─pkgdown:::build_site_local(...)
#> 4. └─pkgdown::build_reference(...)
#> 5. ├─pkgdown:::unwrap_purrr_error(...)
#> 6. │ └─base::withCallingHandlers(...)
#> 7. └─purrr::map(...)
#> 8. └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#> 9. ├─purrr:::with_indexed_errors(...)
#> 10. │ └─base::withCallingHandlers(...)
#> 11. ├─purrr:::call_with_cleanup(...)
#> 12. └─pkgdown (local) .f(.x[[i]], ...)
#> 13. ├─base::withCallingHandlers(...)
#> 14. └─pkgdown:::data_reference_topic(...)
#> 15. └─pkgdown:::run_examples(...)
#> 16. └─pkgdown:::highlight_examples(code, topic, env = env)
#> 17. └─downlit::evaluate_and_highlight(...)
#> 18. └─evaluate::evaluate(code, child_env(env), new_device = TRUE, output_handler = output_handler)
#> 19. ├─base::withRestarts(...)
#> 20. │ └─base (local) withRestartList(expr, restarts)
#> 21. │ ├─base (local) withOneRestart(withRestartList(expr, restarts[-nr]), restarts[[nr]])
#> 22. │ │ └─base (local) doWithOneRestart(return(expr), restart)
#> 23. │ └─base (local) withRestartList(expr, restarts[-nr])
#> 24. │ └─base (local) withOneRestart(expr, restarts[[1L]])
#> 25. │ └─base (local) doWithOneRestart(return(expr), restart)
#> 26. ├─evaluate:::with_handlers(...)
#> 27. │ ├─base::eval(call)
#> 28. │ │ └─base::eval(call)
#> 29. │ └─base::withCallingHandlers(...)
#> 30. ├─base::withVisible(eval(expr, envir))
#> 31. └─base::eval(expr, envir)
#> 32. └─base::eval(expr, envir)
#> 33. ├─base::try(f1())
#> 34. │ └─base::tryCatch(...)
#> 35. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 36. │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 37. │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 38. └─f1()
#> 39. └─f2()
#> 40. └─f3()
# -------------------------------------------------------------------
if (FALSE) { # \dontrun{
# Unnamed arguments will cause an error
stop_ctx("A", "X")
} # }