teamcapybara/capybara · error · ArgumentError
`switch_to_window` can take either a block or a window, not
Error message
`switch_to_window` can take either a block or a window, not both
What it means
switch_to_window supports two addressing modes - a Capybara::Window object or a block evaluated per window - and explicitly rejects using both at once with ArgumentError before any driver work happens.
Source
Thrown at lib/capybara/session.rb:513
# Switch to the given window.
#
# @overload switch_to_window(&block)
# Switches to the first window for which given block returns a value other than false or nil.
# If window that matches block can't be found, the window will be switched back and {Capybara::WindowError} will be raised.
# @example
# window = switch_to_window { title == 'Page title' }
# @raise [Capybara::WindowError] if no window matches given block
# @overload switch_to_window(window)
# @param window [Capybara::Window] window that should be switched to
# @raise [Capybara::Driver::Base#no_such_window_error] if nonexistent (e.g. closed) window was passed
#
# @return [Capybara::Window] window that has been switched to
# @raise [Capybara::ScopeError] if this method is invoked inside {#within} or
# {#within_frame} methods
# @raise [ArgumentError] if both or neither arguments were provided
#
def switch_to_window(window = nil, **options, &window_locator)
raise ArgumentError, '`switch_to_window` can take either a block or a window, not both' if window && window_locator
raise ArgumentError, '`switch_to_window`: either window or block should be provided' if !window && !window_locator
unless scopes.last.nil?
raise Capybara::ScopeError, '`switch_to_window` is not supposed to be invoked from ' \
'`within` or `within_frame` blocks.'
end
_switch_to_window(window, **options, &window_locator)
end
##
# This method does the following:
#
# 1. Switches to the given window (it can be located by window instance/lambda/string).
# 2. Executes the given block (within window located at previous step).
# 3. Switches back (this step will be invoked even if an exception occurs at the second step).
#
# @overload within_window(window) { do_something }View on GitHub (pinned to 15b5fdb76e)
Solutions
- Pick one mode: switch_to_window(window) to switch to a known window object
- Or switch_to_window { title == 'Chat' } to find and switch by predicate
- Audit helper signatures so the window argument is dropped when a block is given
Example fix
# before
switch_to_window(chat_window) { title == 'Chat' }
# after
switch_to_window(chat_window)
# or
switch_to_window { title == 'Chat' } Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, 'window or block, not both' if window && block_given? switch_to_window(window)
Type guard
def window_arg?(obj) obj.is_a?(Capybara::Window) end switch_to_window(w) if window_arg?(w)
Prevention
- Standardize on one addressing mode per codebase
- Store Window objects from window_opened_by so locator blocks are unnecessary
When it happens
Trigger: switch_to_window(page.windows.last) { title == 'Chat' } - a window argument plus a locator block in the same call; helper methods that always pass a block while callers also supply a window argument.
Common situations: Refactoring between the two addressing modes and leaving both in place; page-object helpers with a default window parameter invoked together with a block.
Related errors
- You must provide a frame element, :parent, or :top when call
- `switch_to_window`: either window or block should be provide
- `switch_to_window` is not supposed to be invoked from `withi
- `#within_window` requires a `Capybara::Window` instance or a
- Window cannot be switched inside a `within_frame` block
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/adbef161a4a4e688.
Report an issue: GitHub.