I use a series of scripts to generate regular reports, and I often want the process to pause at key points—either to check progress or to flag issues that need my attention. One common example involves a lookup table that maps each fundraiser to their team. I append that team information to my reports so I can easily segment the data by team and individual fundraiser.
But what happens when something changes? A new team member joins and isn’t in the lookup table yet. Someone gets married and their last name changes. Suddenly, that person is no longer associated with the correct team, and the report quietly becomes wrong. Here’s how I catch those issues before they slip through.
Build the Data
Portfolio
#| warning: false
#| message: false
# Load the dplyr library
library(dplyr)
# Build a sample portfolio
df <- tibble(fundraiser = c("Carol",
"Bob",
"Rachel"),
constituent = c("Charles Dickens",
"Victor Hugo",
"Jane Austen")
)
# Look at the data
df
Lookup Table
# Create a fundraiser lookup table
lookup <- tibble(fundraiser = c("Carol", "Rachel"),
team = c("Major Giving", "Annual Giving"))
# Look at the data
lookup
Join the Data
Now, let’s see what happens when I join lookup to df.
df <- left_join(df, lookup, by = c("fundraiser" = "fundraiser"))
df
If I wasn’t paying attention, I might keep going, produce a beautifully formatted report, save it to Excel, and only then realize that Bob isn’t connected with a team.
Stopping the Script
There are a few ways to have R stop the script. The basic structure is if a condition exists, then do something. Here, we check for empty strings or NA’s in the data and, if they’re found, stop and display the message.
#| error: true
if(any(df$team == "" | is.na(df$team))) {
stop(paste("Someone is missing a team. Does the lookup table need to be updated?"))
}
This is a simple way to throw an error if something doesn’t look right, but we can take it a step further by listing the names of the fundraisers who are missing a team.
#| error: true
if(any(df$team == "" | is.na(df$team))) {
stop(
paste(
"These fundraisers have no team:",
paste(df$fundraiser[df$team == "" | is.na(df$team)], collapse = ", ")
)
)
}
Wrapping it in a Function
It is conceiveable that we might want to run similar checks on other columns in the data. Here is a function that does the same process, but wrapped in a more flexible package that can be pointed at any data set, name column, and target column.
check_missing <- function(data, name_col, target_col) {
# Convert column names to symbols
name_col <- rlang::ensym(name_col)
target_col <- rlang::ensym(target_col)
# Identify rows where the target column is blank or NA
missing_rows <- data |>
dplyr::filter(is.na(!!target_col) | !!target_col == "") |>
dplyr::pull(!!name_col)
# If any are missing, stop with a helpful message
if(length(missing_rows) > 0) {
stop(
paste(
"These entries have missing values in", rlang::as_string(target_col), "-", paste(missing_rows, collapse = ", ")
)
)
}
invisible(TRUE)
}
#| error: true
check_missing(df, fundraiser, team)

