Quick summary
Summarize this blog with AI
Introduction
An if condition must resolve to one nonmissing logical value. “Argument is of length zero” means the condition produced no values—for example, comparing an empty numeric vector. It is different from an undefined name, a missing function argument, or an NA condition. The examples below deliberately catch known errors so the lesson continues.
Tested with R 4.5.1. Run the following code blocks in order. All inputs are included.
Reproduce the exact failure
Start with a defined, empty vector. Nothing needs to be downloaded or inferred from an undefined variable.
x <- numeric(0)
message <- tryCatch(if (x > 0) "positive", error = conditionMessage)
print(message) # "argument is of length zero" in an English R session
stopifnot(grepl("length zero", message, fixed = TRUE))
stopifnot(identical(x > 0, logical(0)))
The comparison produces logical(0). Checking length(x) == 0 is safe because that comparison itself produces one TRUE or FALSE.
Separate four different conditions
Record the exact failing expression and inspect its type and length. Error messages can be translated by the R locale.
cases <- list(empty = logical(0), missing = NA, several = c(TRUE, FALSE))
messages <- vapply(cases, function(condition) {
tryCatch(if (condition) "yes" else "no", error = conditionMessage)
}, character(1))
print(messages)
stopifnot(grepl("length zero", messages[["empty"]], fixed = TRUE))
stopifnot(grepl("missing value", messages[["missing"]], fixed = TRUE))
stopifnot(grepl("length > 1", messages[["several"]], fixed = TRUE))
f <- function(x) length(x)
missing_argument <- tryCatch(f(), error = conditionMessage)
stopifnot(grepl("argument", missing_argument, fixed = TRUE))
The last call never supplies x, so it has a missing-argument error. Similarly, list()[[1]] fails at indexing before any surrounding if condition runs. Reproduce the operation that actually fails, rather than attaching one error label to all empty inputs.
Validate a scalar before comparing it
This function requires one finite numeric value. It rejects empty, vector, missing, infinite and character inputs instead of inventing a default.
is_positive <- function(x) {
if (!is.numeric(x) || length(x) != 1L || is.na(x) || !is.finite(x)) {
stop("x must be one finite numeric value")
}
x > 0
}
stopifnot(is_positive(3), !is_positive(0), !is_positive(-1))
for (bad in list(NULL, numeric(0), c(1, 2), NA_real_, Inf, "3")) {
result <- tryCatch(is_positive(bad), error = function(e) e)
stopifnot(inherits(result, "error"))
}
The scalar operators || stop evaluating once a rejection condition is true. This prevents later checks from trying to use an empty or multi-element result as one condition.
Choose explicit whole-vector semantics
For a vector, decide whether the question means any value or every value. Empty input and missing values need their own policies.
values <- c(-1, NA, 3)
print(any(values > 0, na.rm = TRUE)) # TRUE
print(all(values > 0, na.rm = TRUE)) # FALSE
stopifnot(!any(logical(0)), all(logical(0)))
observed <- values[!is.na(values)]
all_observed_positive <- length(observed) > 0L && all(observed > 0)
stopifnot(!all_observed_positive)
stopifnot(!isTRUE(NA), !isTRUE(logical(0)))
all(logical(0)) is TRUE by definition; the explicit length guard above requires at least one observed value. isTRUE() is appropriate only when treating anything other than one TRUE as false matches the application. It should not conceal a missing required input. Use traceback() after an uncaught error to locate the caller, then inspect the data before that condition.