Sort through R Error Headaches

Marc Los Huertos

EA030 · Compiled 2026-04-23

Error Anatomy Errors vs Warnings vs Messages Debugging Strategy Error Catalogue Warning Catalogue Errors in RMarkdown Debugging Tools Getting Help

🎯 Learning Outcomes

  1. Distinguish errors, warnings, and messages and explain why each requires a different response.
  2. Decode the structure of an R error message — identify what failed, where, and why.
  3. Apply a systematic five-step debugging strategy to any unfamiliar error.
  4. Recognize and fix the 15 most common R errors encountered in environmental data analysis.
  5. Interpret the most important warnings — especially those that produce silent incorrect results.
  6. Diagnose and resolve RMarkdown-specific knit failures.
  7. Use traceback(), browser(), and options(warn = 2) for deeper debugging.
  8. Write a minimal reproducible example (reprex) to ask for help effectively.

What this module covers. Every R user spends a substantial fraction of their time reading error messages. Most errors fall into a small set of recurring categories — and once you can recognize them, fixing them takes seconds rather than hours. This module builds two things: a mental model for reading any error, and a practical catalogue of the errors you will encounter most often in EA030 analyses.


1. The Anatomy of an R Error

Before looking at specific errors, it helps to understand what an error message is actually telling you. R error messages have a consistent structure — but they use technical vocabulary that can make them feel more opaque than they are.

# Deliberately trigger a common error
my_data <- data.frame(site = c("A", "B", "C"), temp = c(12.1, 14.5, 11.8))
mean(my_data$temperture)  # typo: "temperture" instead of "temp"
## [1] NA

Error in mean(my_data$temperture) : argument “x” is missing, with no default

Every error message has at most three parts:

1. Error in [function call]: — tells you which function call failed. mean(my_data$temperture) is the immediate call, but the root cause may be several steps earlier.

2. The message itself — describes what went wrong. The vocabulary is terse and sometimes misleading (this message says “argument missing” but the real problem is the column doesn’t exist — $temperture returns NULL, and mean(NULL) has no x argument).

3. A backtrace (not always shown) — a chain of function calls that led to the failure. In RMarkdown knit output you sometimes see Backtrace: followed by numbered frames. Read from the bottom up — the bottom frame is the deepest point of failure.

📌 The error message describes a symptom, not always the cause. argument "x" is missing means R received NULL where it expected a vector. The cause is the typo $temperture. Always ask: “what value was passed to this function, and where did that value come from?”

Reading the call chain

# A deeper error: function calls inside a pipeline
library(dplyr)
wq <- data.frame(site = c("A","B"), do_mgl = c(7.2, 8.1))

wq |>
  group_by(site) |>
  summarise(mean_do = mean(DO_mgl))   # wrong column name
## Error in `summarise()`:
## ℹ In argument: `mean_do = mean(DO_mgl)`.
## ℹ In group 1: `site = "A"`.
## Caused by error:
## ! object 'DO_mgl' not found

Error in summarise(): ℹ In argument: mean_do = mean(DO_mgl).
Caused by error in mean():
! object ‘DO_mgl’ not found

Modern dplyr (>= 1.1) formats errors with nested Caused by lines — the innermost Caused by is the actual problem. Here the chain is: summarise() called mean(), which tried to find DO_mgl, which does not exist (the column is named do_mgl).


2. Errors, Warnings, and Messages

R produces three distinct levels of output that are easy to confuse.

Errors — execution stops

Error in read.csv(“data/water_quality.csv”) : cannot open file ‘data/water_quality.csv’: No such file or directory

An error halts execution immediately. No output is produced. Nothing after the error line runs. You must fix the error before continuing.

Warnings — execution continues, but something is wrong

Warning message: In log(x) : NaNs produced

A warning means R completed the operation but encountered something suspicious. The result is returned — but it may be wrong. Warnings deserve the same attention as errors. Silent incorrect results caused by ignored warnings are among the hardest bugs to find.

# This runs without error but produces silent NaN values
x <- c(5, 2, -1, 8, -3, 4)
log_x <- log(x)   # Warning: NaNs produced for negative values
## Warning in log(x): NaNs produced
log_x             # The NaNs are in your data now
## [1] 1.6094379 0.6931472       NaN 2.0794415       NaN 1.3862944

⚠️ warning = FALSE in knitr hides warnings from the rendered document — it does NOT suppress the underlying problem. Many module templates include warning = FALSE in the setup chunk so output is cleaner. This is fine once a module is working, but while you are developing code, always run with warning = TRUE or check warnings() after execution.

Messages — informational, not a problem

── Attaching core tidyverse packages ──────────── tidyverse 2.0.0 ── ✔ ggplot2 3.5.1 ✔ purrr 1.0.2
✔ tibble 3.2.1 ✔ dplyr 1.1.4
✔ tidyr 1.3.0 ✔ stringr 1.5.1

A message is purely informational — R is telling you something happened (a package loaded, a file was written, a model converged). Messages do not indicate problems. Suppress them in final reports with message = FALSE in the chunk header.

Type Execution Result returned? Action required?
Error Stops No Yes — always
Warning Continues Yes, possibly wrong Usually yes
Message Continues Yes, correct No

3. A Systematic Debugging Strategy

When you encounter an unfamiliar error, resist the urge to immediately Google the message. Work through these steps first — you will solve 80% of errors in under two minutes.

  1. Read the full message. The complete error text, not just the first line. The most useful information is often in the Caused by or In argument lines that follow. Scroll up in the console — the error may be preceded by useful context.
  2. Identify the immediate failing call. Look at Error in [X]: — X is the function that crashed. Find that call in your code. Is it spelled correctly? Are you calling a function that is not loaded?
  3. Inspect the inputs to that call. Run the lines before the error in isolation. Print the objects being passed to the failing function. Ask: what type is it? What does it contain? Use class(), str(), head(), dim(), and is.na() on the inputs.
  4. Simplify. Replace your real data with the smallest possible example that reproduces the error. If the error disappears with simple data, the bug is in your data, not your code.
  5. Search with the exact error text. Copy just the error message (not the function call, which is specific to your code) and search Google or Stack Overflow. Add “R” and the relevant package name. Most common errors have been answered dozens of times.

Applying the strategy: a worked example

Here is a realistic EA030 scenario.

# You are trying to compute monthly means from a CSV export
# that has the date column stored as character
sensor_df <- data.frame(
  timestamp = c("2024-01-15", "2024-01-16", "not-a-date",
                "2024-02-03", "2024-02-04"),
  temp_C    = c(12.1, 13.4, 11.8, 9.2, 10.5)
)

library(lubridate)
library(dplyr)

sensor_df |>
  mutate(month = month(ymd(timestamp))) |>
  group_by(month) |>
  summarise(mean_temp = mean(temp_C))
## # A tibble: 3 × 2
##   month mean_temp
##   <dbl>     <dbl>
## 1     1     12.8 
## 2     2      9.85
## 3    NA     11.8

Step 1 — read the full output. The code ran without error, but there is likely a warning (run with warning = TRUE).

Step 2 — find the failing call. The warning would say 1 failed to parse in ymd(). The timestamp "not-a-date" could not be parsed.

Step 3 — inspect the inputs. Run ymd(sensor_df$timestamp) alone and inspect the output — you will see an NA in position 3.

Step 4 — simplify. The problem is one bad string in your data column. Check with sensor_df$timestamp[is.na(ymd(sensor_df$timestamp))] to find and fix it.

# Fix: identify the bad row before computing
bad_rows <- which(is.na(ymd(sensor_df$timestamp)))
cat("Rows with unparseable timestamps:", bad_rows, "\n")
## Rows with unparseable timestamps: 3
cat("Values:  ", sensor_df$timestamp[bad_rows], "\n")
## Values:   not-a-date
# Then either fix the data or filter it out
sensor_clean <- sensor_df[-bad_rows, ]
sensor_clean |>
  mutate(month = month(ymd(timestamp))) |>
  group_by(month) |>
  summarise(mean_temp = mean(temp_C))
## # A tibble: 2 × 2
##   month mean_temp
##   <dbl>     <dbl>
## 1     1     12.8 
## 2     2      9.85

4. The Error Catalogue

The following errors account for the vast majority of what you will encounter in EA030. Each entry shows the exact message R produces, the most common cause, and the fix.


Error object ‘x’ not found ●●●●● most common

What it means. R looked for an object named x in the current environment and could not find it. The object either was never created, was created in a different session, or its name is misspelled.

Most common causes.

# Cause 1: typo in object name
temperature_data <- c(12, 14, 11)
mean(temperture_data)   # Error: object 'temperture_data' not found

# Cause 2: chunk ran out of order in RMarkdown — object from chunk 5
# is referenced in chunk 3, which runs first during knit
# Fix: re-order your chunks so dependencies flow top to bottom

# Cause 3: object created inside an if() or for() block with wrong scope
for (i in 1:5) { result_i <- i^2 }
result_i   # Works — last iteration's value is in global env
# But if the for loop never ran (e.g., empty vector), result_i won't exist

# Cause 4: package function used before library() call
mutate(df, x = x * 2)   # Error if dplyr is not loaded

Fix. Run ls() to list objects in your current environment. Check spelling. In RMarkdown, ensure the chunk that creates the object runs before the chunk that uses it.


Error could not find function “x” ●●●●○ very common

What it means. R could not find a function named x. Unlike “object not found” (which applies to data), this applies to functions — it almost always means a package is not loaded.

Most common causes.

# Cause 1: forgot library()
ggplot(df, aes(x = site, y = do_mgl)) + geom_col()
# Error: could not find function "ggplot"
# Fix:
library(ggplot2)   # or library(tidyverse)

# Cause 2: typo in function name
raed_csv("data/wq.csv")       # should be read_csv
filter(df, siet == "Upland")  # filter is fine, but check the column name typo too

# Cause 3: package installed but namespace not loaded
vegan::rarefy(comm, sample = 50)   # This works without library(vegan)
rarefy(comm, sample = 50)           # Error — function not in search path

Fix. Add library(packagename) near the top of your script, before any code that uses the package. Check spelling with ?function_name — if the help page opens, the function exists.


Error cannot open file ‘…’: No such file or directory ●●●●○ very common

What it means. R tried to read a file and could not find it at the path you specified.

Most common causes.

# Cause 1: wrong working directory
# R is looking in the wrong folder
read.csv("data/water_quality.csv")
# Fix: check and set your working directory
getwd()
setwd("/correct/path/to/project")
# Better: use RStudio Projects so working directory is always the project root

# Cause 2: path is relative to the wrong location
# In RMarkdown, the working directory during knit is the .Rmd file's location,
# not your console working directory
read.csv("../data/water_quality.csv")   # go up one level, then into data/

# Cause 3: typo in filename (including wrong case — R is case-sensitive on Linux/Mac)
read.csv("data/Water_Quality.csv")   # file is actually water_quality.csv

Fix. Run list.files("data/") to see exactly what is in the folder. Use file.exists("data/water_quality.csv") to test a specific path before reading.

# Defensive pattern
path <- "data/water_quality.csv"
if (!file.exists(path)) stop("File not found: ", path)
df <- read.csv(path)

Error object of type ‘closure’ is not subsettable ●●●○○ common

What it means. You tried to use [ or $ on a function rather than a data frame or vector. A “closure” is R’s technical term for a function.

Most common cause. A variable name shadows a function name — you used data, df, filter, mean, or another common name for your data object and for a function, and R found the function first.

# Cause: common variable names that shadow functions
data <- read.csv("myfile.csv")   # 'data' is also a base R function
data$site                        # Error: object of type 'closure' is not subsettable

# Fix: use a more specific variable name
wq_data <- read.csv("myfile.csv")
wq_data$site   # works fine

# Other names to avoid as variable names:
# c, t, T, F, mean, sum, min, max, df, data, matrix, list, table

Fix. Rename your variable to something that does not clash with a built-in function. Run is.function(data) — if it returns TRUE, data is being interpreted as the function.


Error replacement has X rows, data has Y rows ●●●○○ common

What it means. You tried to assign a vector to a data frame column, but the vector length does not match the number of rows.

wq <- data.frame(site = c("A","B","C","D"), do_mgl = c(7,8,6,9))

# Cause 1: vector is the wrong length
wq$log_do <- log(c(7, 8))   # Error: replacement has 2 rows, data has 4

# Cause 2: filter() or subset() happened upstream and changed nrow
wq_sub <- wq[wq$do_mgl > 7, ]   # now 2 rows
wq$flag <- wq_sub$do_mgl > 7    # wq still has 4 rows — mismatch

# Fix: always operate on the same object
wq$log_do <- log(wq$do_mgl)           # same-length operation
wq$flag   <- wq$do_mgl > 7            # correct: compares within the same df

Fix. Check length() of the vector and nrow() of the data frame before assigning. When in doubt, use mutate() inside a dplyr pipeline — it always operates on the rows of the piped object.


Error non-numeric argument to binary operator ●●●○○ common

What it means. You tried to do arithmetic (+, -, *, /, ^) on something that is not a number — most often a character string or a factor.

wq <- data.frame(
  site   = c("A","B","C"),
  temp   = c("12.1", "14.5", "11.8")   # stored as character, not numeric!
)

mean(wq$temp)        # returns NA with a warning
wq$temp_scaled <- wq$temp * 0.1  # Error: non-numeric argument to binary operator

Diagnosis and fix.

class(wq$temp)      # "character" — that's the problem
str(wq)             # shows all column types at once

# Fix 1: convert the column
wq$temp <- as.numeric(wq$temp)

# Fix 2: fix at import (readr does this automatically for properly formatted CSVs)
library(readr)
wq <- read_csv("wq.csv")   # detects column types automatically

# Fix 3: check for stray characters that prevent coercion
# If as.numeric() produces NAs, the column contains non-numeric strings
wq$temp[is.na(as.numeric(wq$temp))]   # shows the problematic values

Error undefined columns selected ●●○○○ moderate

What it means. You used [ with a column name or number that does not exist in the data frame.

df <- data.frame(site = "A", temp_C = 12, do_mgl = 8)

df[, "temperature"]   # Error: undefined columns selected — column is "temp_C"
df[, 5]               # Error: there is no 5th column

# With $, the behavior is different — silently returns NULL
df$temperature        # NULL (no error!)

Fix. Use names(df) or colnames(df) to check exact column names. The $ operator’s silent NULL return for missing columns is more dangerous than this error, because it propagates invisibly through your pipeline.

# Defensive check
col <- "temperature"
if (!col %in% names(df)) stop("Column '", col, "' not found in data frame")

Error arguments imply differing number of rows: X, Y ●●○○○ moderate

What it means. You tried to create a data.frame() from vectors of different lengths, and none of them is a multiple of the others (so recycling cannot resolve it).

data.frame(
  site  = c("A", "B", "C"),
  temp  = c(12.1, 14.5),       # only 2 values — Error
  do_mg = c(7.2, 8.1, 6.9)
)

Fix. All vectors passed to data.frame() must have the same length. Check length() on each vector before constructing the frame. The error message tells you the conflicting lengths.


Error $ operator is invalid for atomic vectors ●●○○○ moderate

What it means. You used $ on a plain vector (numeric, character, or logical), not a list or data frame. $ only works on named list-like objects.

# Cause 1: trying to use $ on a vector returned by a function
result <- c(mean = 12.4, sd = 2.1)   # named numeric vector, not a list
result$mean   # Error: $ operator is invalid for atomic vectors

# Fix: use [[ ]] or named indexing
result[["mean"]]    # 12.4
result["mean"]      # returns named vector

# Cause 2: function returns a vector, not a data frame
summary_values <- tapply(wq$temp, wq$site, mean)
summary_values$A    # Error: tapply returns an array, not a data frame
summary_values["A"] # Correct

Error package ‘X’ was built under R version Y.Z Warning ●○○○○ occasional

What it means. The package was compiled for a newer (or older) version of R than you are running. This is a warning, not an error — the package usually still loads and works. It becomes a problem if the package uses features that do not exist in your R version.

Fix. Update R and/or the package. Run update.packages() to update all installed packages. If you need a specific older version for reproducibility, use renv.


Error there is no package called ‘X’ ●●○○○ moderate

What it means. You called library(X) but package X is not installed on this machine.

library(vegan)
# Error in library(vegan) : there is no package called 'vegan'

Fix.

install.packages("vegan")   # installs from CRAN
library(vegan)              # then load it

# For GitHub-only packages:
# install.packages("remotes")
# remotes::install_github("username/packagename")

In RMarkdown, include install lines commented out with a note:

# Run this line once to install, then comment it out:
# install.packages("vegan")
library(vegan)

5. The Warning Catalogue

Warnings are more insidious than errors because R continues running and returns a result — but the result may be silently wrong. These are the most important warnings to understand.


Warning NAs introduced by coercion ●●●●○ very common

What it means. as.numeric() (or as.integer()) could not convert one or more values — they became NA. This almost always means your column contains non-numeric strings mixed in with numbers.

x <- c("12.1", "14.5", "N/A", "11.8", "--", "10.2")
as.numeric(x)
# [1] 12.1 14.5   NA 11.8   NA 10.2
# Warning: NAs introduced by coercion

This is how you clean sensor data with flags. Find and inspect the non-numeric values, decide whether to recode them, then convert.

# Find which values will not convert
x[is.na(suppressWarnings(as.numeric(x)))]
# [1] "N/A" "--"

# Recode to NA explicitly, then convert
x_clean <- ifelse(x %in% c("N/A", "--", ""), NA_character_, x)
as.numeric(x_clean)   # no warning; NAs are intentional

Warning In log(x) : NaNs produced ●●●○○ common

What it means. You took the log (or sqrt) of a negative number or zero. log(0) returns -Inf; log(-1) returns NaN (Not a Number). Both propagate silently through arithmetic.

conc <- c(0.5, 1.2, 0.0, -0.1, 2.3)   # zero and negative from a sensor glitch
log(conc)
# [1] -0.6931  0.1823    -Inf    NaN  0.8329
# Warning message: In log(conc) : NaNs produced

Fix. Investigate why negatives or zeros exist. Sensor values of 0 or below the detection limit need special handling (see the Non-Detects module). Filter or recode before transforming.

conc_clean <- conc[conc > 0]   # remove zeros and negatives
log(conc_clean)                # no warning

Warning longer object length is not a multiple of shorter object length ●●●○○ common

What it means. You performed a vectorized operation on two vectors of different lengths, and R recycled the shorter vector to match the longer one — but the lengths are not evenly divisible. The recycling probably produced wrong results.

a <- c(1, 2, 3, 4, 5, 6, 7)
b <- c(10, 20, 30)
a + b   # Warning: longer object length is not a multiple of shorter
# [1] 11 22 33 14 25 36 17
# R recycled b as 10, 20, 30, 10, 20, 30, 10 — almost certainly not intended

This warning signals a logic error, not a data glitch. Check that your vectors are the lengths you intend.


Warning Removed X rows containing missing values (geom_point) ●●●○○ common

What it means. ggplot2 encountered NA values in the columns mapped to x or y aesthetics. It silently dropped those rows from the plot. This is often expected behavior — but always ask whether the NAs are intentional or indicate a parsing error upstream.

# Diagnosis: how many NAs are there and where?
sum(is.na(df$do_mgl))
which(is.na(df$do_mgl))   # which rows

# If the NAs came from a failed date parse, for example,
# fix the parse rather than just suppressing the ggplot warning

Warning 1 failed to parse. / X failed to parse. ●●●●○ very common

What it means. lubridate’s ymd(), mdy(), etc. could not parse one or more values — they became NA. This is the single most important warning in time-series analysis because it means you have lost data points silently.

dates <- c("2024-01-15", "2024-02-20", "20240330", "bad date")
ymd(dates)
# [1] "2024-01-15" "2024-02-20" "2024-03-30" NA
# Warning message: 1 failed to parse.

Fix. Find and inspect the failed values before proceeding.

parsed <- ymd(dates, quiet = TRUE)
dates[is.na(parsed)]   # "bad date"
# Fix, recode, or document the bad value, then re-parse

6. Errors in RMarkdown

RMarkdown introduces a second layer of errors on top of R errors. A document that runs fine in the console may fail during knit.

The chunk order problem

When you knit, RMarkdown runs every chunk from top to bottom in a fresh R session. Objects created interactively in your console do not exist during knit.

Error in mean(pm_data$temp) : object 'pm_data' not found

This means pm_data was created in a chunk that runs after the chunk that uses it, or it was created interactively but never put in a chunk. Fix: always create objects before using them. Read data in an early chunk.

The eval=FALSE trap


``` r
pm_data <- read_csv("data/pm25.csv")   # this chunk does NOT run during knit
ggplot(pm_data, ...)   # Error: object 'pm_data' not found
## Error in `ggplot()`:
## ! could not find function "ggplot"

If eval=FALSE was added to a data-loading chunk to “skip” a slow step, the object is never created during knit. Remove eval=FALSE or use cache=TRUE instead.

Catching knit errors efficiently

💡 Use error = TRUE in the setup chunk while developing. Setting knitr::opts_chunk$set(error = TRUE) allows the document to knit even when chunks produce errors — the error message is printed inline rather than halting the knit. This lets you see all errors in one pass. Remove it (or set error = FALSE) once your document is working correctly.

# In your setup chunk during development:
knitr::opts_chunk$set(
  echo    = TRUE,
  error   = TRUE,    # show errors inline instead of halting
  warning = TRUE,    # show warnings so you can find them
  message = FALSE
)

The working directory in RMarkdown

During knit, the working directory is the directory containing the .Rmd file, not your RStudio working directory. Any file paths that work in the console may fail during knit.

# Console: works (working directory is project root)
read.csv("data/wq.csv")

# Knit: fails if Rmd is in project root (same, ok) but fails if Rmd is in a subfolder
# Fix: use here::here() which always resolves from the project root
library(here)
read.csv(here("data", "wq.csv"))   # works regardless of Rmd location

7. Debugging Tools

For errors that do not resolve quickly with the five-step strategy, R provides several tools for deeper investigation.

traceback() — see the call stack after an error

After an error occurs interactively, run traceback() immediately (before running any other command). It prints the full chain of function calls that led to the error, from the outermost call down to the line that failed.

# After getting an error, immediately run:
traceback()
# Output (read from bottom to top):
# 3: stop("argument must be numeric")
# 2: mean.default(my_data$tempC)
# 1: mean(my_data$tempC)

The bottom frame is where R stopped. Work upward to understand what called what.

options(warn = 2) — convert warnings to errors

Warnings are easy to miss. Setting options(warn = 2) makes every warning behave as an error, with a full traceback. This is the fastest way to find where a warning originates.

options(warn = 2)    # warnings become errors with traceback
log(c(1, -1, 2))     # now produces a full traceback to the negative value
options(warn = 0)    # reset to normal behavior afterward

browser() — pause execution inside a function

Insert browser() anywhere in your code (including inside a custom function) and execution will pause at that point, dropping you into an interactive browser where you can inspect all local variables.

my_fn <- function(x) {
  x_clean <- x[x > 0]
  browser()              # execution pauses here; type variable names to inspect
  log(x_clean)
}
my_fn(c(1, -1, 2))
# Called from: my_fn(c(1, -1, 2))
# Browse[1]> x_clean     # inspect the variable
# [1] 1 2
# Browse[1]> Q           # quit the browser

8. Getting Help Effectively

The R help system

?mean            # help page for the mean() function
??rarefaction    # search all help pages for the word "rarefaction"
help(package = "vegan")    # all functions in a package
vignette("diversity-vegan")  # package vignette with worked examples

Writing a minimal reproducible example (reprex)

When you need to ask for help — from a classmate, instructor, or Stack Overflow — a reprex (minimal reproducible example) is the most important skill. A good reprex:

  1. Is self-contained — contains all the data and code needed to reproduce the error, without requiring access to your files.
  2. Is minimal — strips out everything not relevant to the problem.
  3. Shows the error — actually produces the error when run by someone else.
# Bad: "my code doesn't work" + 200 lines of code + a file path no one can access

# Good reprex:
library(dplyr)
df <- data.frame(site = c("A","B"), do_mgl = c(7.2, 8.1))
df |> summarise(mean_do = mean(DO_mgl))
# Error: object 'DO_mgl' not found
# I expect this to work but 'DO_mgl' is not found even though I can see it in df

The reprex package (part of the tidyverse) can format your reprex automatically for pasting into GitHub or Stack Overflow:

# install.packages("reprex")
library(reprex)
reprex({
  df <- data.frame(site = c("A","B"), do_mgl = c(7.2, 8.1))
  df |> dplyr::summarise(mean_do = mean(DO_mgl))
})

💡 The act of writing a reprex often solves the problem. Stripping your code down to the minimal example that reproduces the error forces you to understand exactly what is failing and why. It is very common to solve your own bug while writing the reprex.


Summary

Debugging quick reference

💬 Check your understanding

  1. You run your RMarkdown document and get Error: object 'wq_clean' not found during knit, but the same code works fine when you run chunks interactively. What is the most likely cause, and how would you fix it?
  2. Your mutate() call runs without error and produces a new column, but when you check the data, roughly 15% of values in the new column are NA where you expected numbers. No error or warning appeared. What knitr setting may have hidden a warning, and how would you find the source of the NAs?
  3. A classmate shows you this error: Error in data.frame(...) : arguments imply differing number of rows: 48, 50. Walk them through the five-step debugging strategy: what specific checks would you run at step 3?
  4. You want to post a question about an error to Stack Overflow. Describe the three properties of a good reprex and write a two-line reprex for this error: Error in group_by(site) : could not find function "group_by".
  5. What is the difference between options(warn = 0), options(warn = 1), and options(warn = 2)? When would you use each?