Skip to content

Functions like starts_with(), contains() or matches() are selection helpers that only work in a selection context, e.g. dplyr::select() or the cols argument of tidyr::pivot_longer().

Using a selection helper anywhere else results in an error:

starts_with("foo")
#> Error:
#> ! `starts_with()` must be used within a *selecting* function.
#> i See
#>   <https://tidyselect.r-lib.org/reference/faq-selection-context.html>
#>   for details.

mtcars[contains("foo")]
#> Error:
#> ! `contains()` must be used within a *selecting* function.
#> i See
#>   <https://tidyselect.r-lib.org/reference/faq-selection-context.html>
#>   for details.

subset(mtcars, select = matches("foo"))
#> Error:
#> ! `matches()` must be used within a *selecting* function.
#> i See
#>   <https://tidyselect.r-lib.org/reference/faq-selection-context.html>
#>   for details.

If you see this error, you may have used a selection helper in the wrong place, possibly as the result of a typo (e.g. misplaced comma or wrong argument name). Alternatively, you may be deliberately trying to reduce duplication in your code by extracting out a selection into a variable:

my_vars <- c(name, species, ends_with("color"))
#> Error in eval(expr, envir, enclos): object 'name' not found

To make this work you’ll need to do two things:

  • Wrap the whole thing in a function

  • Use any_of() or all_of() instead of bare variable names

my_vars <- function() {
  c(any_of(c("name", "species")), ends_with("color"))
}
dplyr::select(starwars, my_vars())
#> # A tibble: 87 x 5
#>   name           species hair_color skin_color  eye_color
#>   <chr>          <chr>   <chr>      <chr>       <chr>    
#> 1 Luke Skywalker Human   blond      fair        blue     
#> 2 C-3PO          Droid   <NA>       gold        yellow   
#> 3 R2-D2          Droid   <NA>       white, blue red      
#> 4 Darth Vader    Human   none       white       yellow   
#> # i 83 more rows