dplyr column not found
Matches: Can't find column|Column .* doesn't exist
WHAT THIS ERROR MEANS
dplyr can't find a column you referenced by name. This usually means a typo or the column was removed in a prior step.
WHY IT HAPPENS — 4 COMMON CAUSES
1. An earlier stage dropped the column
select() keeps only what you name, and summarise() keeps only the grouping variables plus what it computes. Both silently discard everything else, so a column present in the source data can be gone by the time the failing verb runs.
2. A rename happened upstream
rename(), janitor::clean_names() and the .names argument of across() all change column names mid-pipeline. clean_names() in particular rewrites Total Revenue to total_revenue, which breaks any later reference to the original spelling.
3. The name differs from what you see
Names read from Excel and CSV often carry trailing spaces, non-breaking spaces, or a byte-order mark on the first column. These are invisible in the RStudio viewer but make the name a different string.
4. The column is being masked by an environment variable
Tidy evaluation looks in the data first and the calling environment second. If a local variable shares a column’s name, code can silently use the wrong one — and when the column really is absent, the error names something you can see defined in your session, which is confusing.
HOW TO DIAGNOSE WHICH ONE IT IS
- Run names(df) on the original data first to confirm the column exists at the start.
- Bisect the pipe: run it up to the first verb, then the second, checking names() at each stage until the column disappears.
- Insert a checkpoint mid-pipe without breaking it — df |> select(a, b) |> print() |> mutate(...) — or use dplyr::glimpse().
- Suspect invisible characters? dput(names(df)) prints the exact strings, escapes and all.
- Force a column lookup with .data$revenue to rule out an environment variable of the same name.
HOW TO FIX IT
1. Check available columns with names(df) or colnames(df).
2. Look for typos in the column name.
3. Make sure a prior step didn't rename or remove the column.
CODE EXAMPLES
df %>% select(reveneu) # typo
df %>% select(revenue) # correct name
MORE SCENARIOS THAT TRIGGER THIS
summarise() dropped the columns you needed later
df |> group_by(region) |> summarise(total = sum(revenue)) |> mutate(margin = total / units) # Error: object 'units' not found
df |> group_by(region) |> summarise(total = sum(revenue), units = sum(units)) |> mutate(margin = total / units)
summarise() returns only the grouping variables and the summaries you asked for. Anything you need downstream has to be summarised too — there is no implicit carry-through.
Selecting columns that may or may not be present
df |> select(region, revenue, forecast) # Error if forecast is missing from this month's extract
df |> select(any_of(c("region", "revenue", "forecast")))any_of() ignores names that are not present, while all_of() insists on every one. Use all_of() when a missing column is a genuine data error you want to catch, and any_of() for genuinely optional fields.
PACKAGE-SPECIFIC NOTES
The pronouns .data and .env exist precisely to disambiguate this. .data$revenue always means the column and errors if it is missing; .env$revenue always means the variable in the calling scope. Both are essential when writing functions that take column names as arguments, where you should also reach for {{ }} to embrace an argument, or the .data[[col]] form when the name arrives as a string. data.table reports a different message for the same situation, naming the column it could not find in the j expression.
FUNCTIONS WORTH KNOWING
names()glimpse()any_of()all_of()starts_with()rename()janitor::clean_names()FREQUENTLY ASKED QUESTIONS
Why does the column show in View(df) but dplyr cannot find it?
Almost always an invisible character in the name — a trailing space, a non-breaking space from a web copy-paste, or a UTF-8 BOM on the first column of a CSV. dput(names(df)) reveals them. janitor::clean_names() normalises the lot in one step.
Should I use all_of() or any_of()?
all_of() errors when a named column is missing, which is what you want for required fields. any_of() skips missing names quietly, which suits optional ones. Bare character vectors without either are ambiguous and now warn.
How do I reference a column whose name is in a variable?
If the variable holds a string, use .data[[col_name]]. If you are writing a function whose caller passes a bare column name, embrace the argument with {{ col }} so tidy evaluation resolves it against the data.
Still stuck?
Paste your code in RChat and the AI will fix this error in context.