Subscript & Indexing Errors

Subscript out of bounds

Matches: subscript out of bounds

WHAT THIS ERROR MEANS

You tried to access an element at a position that doesn't exist — like asking for the 10th element of a 5-element vector.

WHY IT HAPPENS — 4 COMMON CAUSES

1. The index is larger than the object

The literal case: asking for element 10 of a 5-element list. Often the index came from a loop bound computed against a different object, or from a length that changed after a filtering step removed rows.

2. A matrix or data frame indexed on the wrong dimension

df[500, ] and df[, 500] fail differently depending on the shape of your data. Mixing up the row and column position in the bracket is easy when the object is wide and short, or long and narrow, and the error message does not say which dimension overflowed.

3. A name that does not exist in a list

my_list[["revenue"]] raises this when the element is absent, whereas my_list$revenue quietly returns NULL. The double bracket is stricter by design, which makes it the safer choice but also the noisier one.

4. An off-by-one from another language

R indexes from 1, not 0. Ported Python or C loops that run from 0 to n-1 will read one element short at the start and, if adjusted carelessly, one past the end at the finish.

HOW TO DIAGNOSE WHICH ONE IT IS

  1. Check the real size first: length() for vectors and lists, dim() or nrow()/ncol() for matrices and data frames.
  2. Print the index itself immediately before the failing line. In a loop, that is usually where the surprise is.
  3. For lists, names(my_list) shows exactly which keys exist.
  4. Replace a hardcoded loop bound with seq_along(x) or seq_len(nrow(df)) — both are empty-safe and cannot overrun.
  5. If the object shrank unexpectedly, check for a filter or na.omit() step upstream that removed more than you expected.

HOW TO FIX IT

1. Check the length of your object with length() or nrow()/ncol().

2. Make sure your index is within the valid range.

3. Remember R is 1-indexed (first element is [1], not [0]).

CODE EXAMPLES

BAD — THIS CAUSES THE ERROR
x <- c(1, 2, 3)
x[5]  # only 3 elements
GOOD — CORRECT APPROACH
x <- c(1, 2, 3)
x[3]  # valid index

MORE SCENARIOS THAT TRIGGER THIS

A loop bound taken from the wrong object

BAD
for (i in 1:length(all_ids)) {
  print(results[[i]])   # results is shorter than all_ids
}
GOOD
for (i in seq_along(results)) {
  print(results[[i]])
}

seq_along() derives the bound from the object being indexed, so the two can never drift apart. It also handles the empty case correctly, whereas 1:length(x) counts backwards from 1 to 0 when x is empty and silently runs one iteration.

A missing list element

BAD
config <- list(host = "localhost", port = 5432)
config[["database"]]
# Error: subscript out of bounds
GOOD
if (!is.null(config$database)) {
  config$database
}

# or supply a default:
config[["database"]] %||% "postgres"

The %||% operator, available from rlang and base R since 4.4, returns the right-hand side when the left is NULL — a concise way to give optional config keys a fallback.

PACKAGE-SPECIFIC NOTES

Plain vectors do not raise this error at all — x[99] on a 3-element vector returns NA rather than stopping, which is why a bad index can travel a long way through numeric code before anything complains. Lists, matrices and data frames are strict. purrr::pluck() offers a middle path, returning NULL for a missing path instead of erroring, and data.table raises a clearer message naming the offending column when you index a column that is not there.

FUNCTIONS WORTH KNOWING

length()nrow()ncol()dim()seq_along()seq_len()names()head()

FREQUENTLY ASKED QUESTIONS

Why does x[99] return NA but my_list[[99]] throws an error?

Single-bracket indexing on an atomic vector is defined to return NA for out-of-range positions, because that behaviour is useful in vectorised arithmetic. Double-bracket extraction promises exactly one element, so there is no sensible value to return and it raises instead.

How do I avoid this in a loop over a list that might be empty?

Use seq_along(x) rather than 1:length(x). When x is empty, seq_along() gives an empty sequence and the loop body never runs; 1:length(x) evaluates to c(1, 0) and runs twice with invalid indices.

I get it from df[, "col"] even though the column is visible in the viewer. Why?

Check for whitespace or a non-breaking space in the column name — names imported from Excel frequently carry trailing spaces. names(df) prints them unquoted, so compare with dput(names(df)) to see the exact strings.

Still stuck?

Paste your code in RChat and the AI will fix this error in context.

Try RChat Free →

RELATED SUBSCRIPT & INDEXING ERRORS