Missing value in condition
Matches: missing value where TRUE\/FALSE needed
WHAT THIS ERROR MEANS
An if statement or while loop received NA instead of TRUE or FALSE. This happens when the condition evaluates to a missing value.
WHY IT HAPPENS — 4 COMMON CAUSES
1. The variable being tested is NA
Any comparison involving NA returns NA, not FALSE. NA > 0 is NA, and if() cannot branch on that. This is deliberate: R does not know whether the missing value exceeds zero, so it refuses to guess.
2. A lookup returned nothing
Indexing a vector with a name that is not there, or matching a value that does not exist, yields NA. If that result feeds straight into a condition, the branch fails rather than taking the else path.
3. A coercion silently produced NA
as.numeric("abc") gives NA with a warning. If the condition tests that result, the failure surfaces at the if() rather than at the conversion, several lines from the real cause.
4. A function returned NA for an all-NA input
mean(x) with any NA in x returns NA unless na.rm = TRUE. Feeding that into a threshold test moves the error downstream of the real problem.
HOW TO DIAGNOSE WHICH ONE IT IS
- Print the condition’s value on its own line before the if(). Seeing NA rather than TRUE/FALSE confirms it immediately.
- Check the input with is.na(x) and sum(is.na(df$col)) to see how widespread the missingness is.
- Use traceback() straight after the error to find which call produced the NA.
- For aggregate functions, test whether adding na.rm = TRUE changes the result — if it does, missing data is your cause.
- In a loop, print the index alongside the value so you can see which iteration breaks.
HOW TO FIX IT
1. Check if your condition variable contains NA.
2. Use is.na() to handle missing values.
3. Add na.rm = TRUE to functions like any() or all().
CODE EXAMPLES
x <- NA
if (x > 0) print("positive")x <- NA
if (!is.na(x) && x > 0) print("positive")MORE SCENARIOS THAT TRIGGER THIS
Guarding a possibly-missing value
if (df$score[i] > 50) {
flag <- "pass"
}
# Error when score is NAif (!is.na(df$score[i]) && df$score[i] > 50) {
flag <- "pass"
}The && operator short-circuits: if the left side is FALSE it never evaluates the right, so the comparison never sees the NA. Using & instead would evaluate both sides and fail.
Vectorised conditions do not have this problem
df$band <- if (df$score > 50) "high" else "low" # condition has length > 1, and NAs break it
df$band <- ifelse(is.na(df$score), NA_character_,
ifelse(df$score > 50, "high", "low"))
# or, clearer with dplyr:
df <- df |> mutate(band = case_when(
is.na(score) ~ NA_character_,
score > 50 ~ "high",
.default = "low"
))if() takes a single value; for a whole column use ifelse() or case_when(), both of which propagate NA per element rather than erroring.
PACKAGE-SPECIFIC NOTES
As of R 4.2 an if() condition of length greater than one is an error rather than a warning, so vectorised conditions now fail loudly — use ifelse() or dplyr::case_when() for column-wise logic. isTRUE(x) is a useful guard because it returns FALSE for NA, NULL and non-logical input instead of raising, which makes it well suited to defensive checks where any non-TRUE value should take the else branch. dplyr::coalesce(x, 0) substitutes a default for NA before the comparison ever happens.
FUNCTIONS WORTH KNOWING
is.na()ifelse()dplyr::case_when()dplyr::coalesce()isTRUE()any()complete.cases()FREQUENTLY ASKED QUESTIONS
Why does NA > 0 return NA instead of FALSE?
NA means the value is unknown, so the comparison genuinely has no answer — the true value might or might not exceed zero. Returning FALSE would assert something R cannot know. This propagation is consistent across arithmetic and comparison operators.
Should I use && or & inside if()?
&& inside if(), because it takes single values and short-circuits, which is what lets !is.na(x) && x > 0 work. & is vectorised and evaluates both sides, so it belongs in ifelse() and filter() rather than in if().
How do I treat NA as FALSE throughout a condition?
Wrap it in isTRUE(), which returns FALSE for anything that is not a single TRUE. In dplyr, filter() already drops NA rows, and tidyr::replace_na() sets an explicit default before the test.
Still stuck?
Paste your code in RChat and the AI will fix this error in context.