teamcapybara/capybara · error · TypeError

Value cannot be an Array when 'multiple' attribute is not pr

Error message

Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}

What it means

Under rack_test, Node#set accepts an Array only for elements that can hold multiple values (i.e. a <select multiple>). If the value is an Array but the element lacks the 'multiple' attribute, it raises TypeError naming the rejected class. This is a fail-fast shape check before any mutation of the DOM.

Source

Thrown at lib/capybara/rack_test/node.rb:37

  def [](name)
    string_node[name]
  end

  def style(_styles)
    raise NotImplementedError, 'The rack_test driver does not process CSS'
  end

  def value
    string_node.value
  end

  def set(value, **options)
    return if disabled? || readonly?

    warn "Options passed to Node#set but the RackTest driver doesn't support any - ignoring" unless options.empty?

    if value.is_a?(Array) && !multiple?
      raise TypeError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
    end

    if radio? then set_radio(value)
    elsif checkbox? then set_checkbox(value)
    elsif range? then set_range(value)
    elsif input_field? then set_input(value)
    elsif textarea? then native['_capybara_raw_value'] = value.to_s
    end
  end

  def select_option
    return if disabled?

    deselect_options unless select_node.multiple?
    native['selected'] = 'selected'
  end

  def unselect_option

View on GitHub (pinned to 15b5fdb76e)

Solutions

  1. Pass a scalar for single-valued fields: find('#topics').set('ruby') or use the select API: page.select('Ruby', from: 'Topics').
  2. Add the multiple attribute to the <select> element if multi-selection is the intended behavior.
  3. Normalize inputs in the helper: collapse arrays to their first element for non-multiple fields (or reject them) before calling set.
  4. Branch on the element: use set(array) only when find_field('X').multiple? is true.

Example fix

# before
find('#topics').set(['ruby', 'go']) # <select> without multiple

# after
select_el = find('#topics')
select_el.multiple? ? select_el.set(['ruby', 'go']) : select_el.set('ruby')
Defensive patterns

Strategy: type-guard

Validate before calling

value = ['ruby', 'go']
node = find('#topics')
raise TypeError, 'Array value needs multiple=true' if value.is_a?(Array) && !node.multiple?
node.set(value)

Type guard

def settable?(node, value)
  !value.is_a?(Array) || node.multiple?
end

Prevention

When it happens

Trigger: find('#topics').set(['ruby', 'go']) where #topics is a <select> without multiple or a text input; a shared fill helper doing fill_in(field, with: params[:tags]) where params[:tags] arrives as an Array for a non-multiple field.

Common situations: A helper written for multi-selects reused on single-selects; the frontend markup changed and lost the multiple attribute; Rails form params (arrays for check-box collections) passed straight into set; data-driven steps where the fixture sometimes yields arrays.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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