teamcapybara/capybara · error · ArgumentError

Invalid option # for :match, should be one of #

Error message

Invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}

What it means

Capybara::Queries::SelectorQuery#assert_valid_keys validates the :match option on every finder/matcher call. :match controls how Capybara resolves a locator that matches multiple elements (or exactly/inexactly), and only :first, :smart, :prefer_exact, :one are accepted (VALID_MATCH in lib/capybara/queries/selector_query.rb:13). Any other value raises ArgumentError before the DOM is searched, so this fails fast on the first query that uses it.

Solutions

  1. Change the value to one of the four accepted symbols: :first, :smart, :prefer_exact, or :one (most common fix is the :smartest -> :smart typo).
  2. Drop the :match option entirely to use the default (:smart).
  3. If you wanted 'any match is fine, take the first', use first('selector') or match: :first instead of inventing a value.
  4. Set it globally with Capybara.match = :first in your setup instead of passing per-call values that drift from the allowed set.

Example fix

# before
find('.item', match: :smartest)

# after
find('.item', match: :smart)
Defensive patterns

Strategy: validation

Validate before calling

VALID_MATCH = %i[first smart prefer_exact one].freeze

match_value = :smart # from config/ENV
raise ArgumentError, "bad :match #{match_value}" unless VALID_MATCH.include?(match_value)
find('.item', match: match_value)

Type guard

def valid_match?(value)
  %i[first smart prefer_exact one].include?(value)
end

Prevention

When it happens

Trigger: Calling any query API that forwards options to SelectorQuery with a bad :match symbol: find('.item', match: :smartest), all('tr', match: :all), first('td', match: :any), have_selector('.x', match: :exact), find(:id, 'foo', match: :one_of) - all raise immediately in assert_valid_keys.

Common situations: Typos (:smartest instead of :smart), copying :match values from other libraries (RSpec's :any, minitest's :one!), or a shared helper/spec_support file hardcoding a value that a Capybara upgrade renamed. Also hit when interpolating a configurable match value from an environment variable without validating it.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21). Data as JSON: /api/errors/d059246c2f5f2c29. Report an issue: GitHub.

Appendix: source

Thrown at lib/capybara/queries/selector_query.rb:347

        filters
      end

      def ordered_results(results)
        case @order
        when :reverse
          results.reverse
        else
          results
        end
      end

      def custom_keys
        @custom_keys ||= node_filters.keys + expression_filters.keys
      end

      def assert_valid_keys
        unless VALID_MATCH.include?(match)
          raise ArgumentError, "Invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
        end

        unhandled_options = @options.keys.reject do |option_name|
          valid_keys.include?(option_name) ||
            expression_filters.any? { |_name, ef| ef.handles_option? option_name } ||
            node_filters.any? { |_name, nf| nf.handles_option? option_name }
        end

        return if unhandled_options.empty?

        invalid_names = unhandled_options.map(&:inspect).join(', ')
        valid_names = (valid_keys - [:allow_self]).map(&:inspect).join(', ')
        raise ArgumentError, "Invalid option(s) #{invalid_names}, should be one of #{valid_names}"
      end

      def filtered_expression(expr)
        conditions = {}
        conditions[:id] = options[:id] if use_default_id_filter?

View on GitHub (pinned to 15b5fdb76e)