Skip to contents

assert is a lightweight toolkit of assertion helpers for checking the inputs and outputs of your functions. Drop a few assertions at the top of a function and get a clear, immediate error when an argument is the wrong type, shape, or value.

Why

Every assertion follows the same simple contract:

  • Checks one thing. Each function tests a single, explicit condition.
  • Returns its input invisibly. Checks can be stacked, one per line, reading like a checklist of preconditions.
  • Fails loudly and clearly. On failure it throws an error that names the offending argument and points at your function, not at assert’s internals.
  • Explicit, readable names. assert_scalar_character(), not assert_chr().

Installation

assert is not on CRAN; install it from GitHub with renv:

# first install renv itself if you don't have it: install.packages("renv")
renv::install("dereckscompany/assert")

Usage

Write assertions at the top of a function. If one fails, it throws an error and the function stops immediately.

box::use(
  assert[
    assert_numeric,
    assert_no_missing_values,
    assert_all_positive,
    assert_same_length
  ]
)

average_price <- function(prices, weights) {
  assert_numeric(prices)
  assert_no_missing_values(prices)
  assert_all_positive(prices)
  assert_same_length(prices, weights)

  return(sum(prices * weights) / sum(weights))
}

average_price(c(10, 20, 30), c(1, 1, 2))
#> [1] 22.5

When an input is invalid, the error names the argument and the calling function:

average_price(c(10, -5, 30), c(1, 1, 2))
#> Error in `average_price()`:
#> ! `prices` must contain only positive values (greater than zero).

Optional arguments

Arguments that default to NULL are optional. Pass null_ok = TRUE to let the assertion accept NULL while still checking any value that is supplied:

box::use(assert[assert_scalar_character, assert_scalar_integer])

connect <- function(host, port = NULL) {
  assert_scalar_character(host)
  assert_scalar_integer(port, null_ok = TRUE)
  return(invisible(TRUE))
}

connect("localhost")          # port omitted — fine
connect("localhost", 8080L)   # port supplied and valid — fine

Stacking checks with the pipe

Because every assertion returns its input invisibly, checks compose naturally with the native pipe |>. Each one validates the value and hands it to the next, so a chain reads like a list of guarantees about the same object:

box::use(assert[assert_data_frame, assert_has_columns, assert_column_types])

people <- data.frame(name = c("Ada", "Alan"), age = c(36L, 41L))

people |>
  assert_data_frame() |>
  assert_has_columns(c("name", "age")) |>
  assert_column_types("character", "name") |>
  assert_column_types("integer", "age") |>
  invisible()

License

MIT © Dereck Mezquita. See LICENSE for details.

Citation

If you use assert in your work, please cite it:

Mezquita, D. (2026). assert. https://github.com/dereckscompany/assert. ORCID: 0000-0002-9307-6762