teamcapybara/capybara · error · ArgumentError

`#within_window` requires a `Capybara::Window` instance or a

Error message

`#within_window` requires a `Capybara::Window` instance or a lambda

What it means

within_window accepts a Capybara::Window instance or a Proc/lambda used as a window locator; anything else raises ArgumentError. The common trigger is a plain String - the Capybara 1.x API allowed within_window('window_name'), which 2.x+ rejects.

Source

Thrown at lib/capybara/session.rb:555

    #     returns a value other than false or nil will be switched to.
    #   @example
    #     within_window(->{ page.title == 'Page title' }) { click_button 'Submit' }
    #   @raise [Capybara::WindowError]         if no window matching lambda was found
    #
    # @raise [Capybara::ScopeError]        if this method is invoked inside {#within_frame} method
    # @return                              value returned by the block
    #
    def within_window(window_or_proc)
      original = current_window
      scopes << nil
      begin
        case window_or_proc
        when Capybara::Window
          _switch_to_window(window_or_proc) unless original == window_or_proc
        when Proc
          _switch_to_window { window_or_proc.call }
        else
          raise ArgumentError, '`#within_window` requires a `Capybara::Window` instance or a lambda'
        end

        begin
          yield if block_given?
        ensure
          _switch_to_window(original) unless original == window_or_proc
        end
      ensure
        scopes.pop
      end
    end

    ##
    # Get the window that has been opened by the passed block.
    # It will wait for it to be opened (in the same way as other Capybara methods wait).
    # It's better to use this method than `windows.last`
    # {https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html#h_note_10 as order of windows isn't defined in some drivers}.
    #

View on GitHub (pinned to 15b5fdb76e)

Solutions

  1. Pass a Window object: within_window(page.windows.last) { ... }
  2. Or a locator lambda: within_window(-> { title == 'popup' }) { ... }
  3. During upgrades, grep the suite for within_window(' to catch every 1.x-style call

Example fix

# before (Capybara 1.x style)
within_window('popup') { click_link 'Close' }

# after
within_window(-> { title == 'popup' }) { click_link 'Close' }
# or
within_window(page.windows.last) { click_link 'Close' }
Defensive patterns

Strategy: type-guard

Validate before calling

raise ArgumentError, 'Window or lambda required' unless window_or_proc.is_a?(Capybara::Window) || window_or_proc.is_a?(Proc)
within_window(window_or_proc) { click_link 'Close' }

Type guard

def window_target?(obj)
  obj.is_a?(Capybara::Window) || obj.is_a?(Proc)
end

Try / catch

begin
  within_window(target) { yield }
rescue ArgumentError
  within_window(-> { title == target }) { yield } # target was a title string
end

Prevention

When it happens

Trigger: within_window('popup') { ... } left over from Capybara 1.x; passing a window handle String or a Symbol; passing page.windows.first.title as the target.

Common situations: Suite upgrades from Capybara 1.x to 2.x+; blog/docs examples predating the API change; old helpers that returned window names being passed through.

Related errors


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