teamcapybara/capybara · error · Capybara::ScopeError
Window cannot be switched inside a `within` block
Error message
Window cannot be switched inside a `within` block
What it means
The second guard in _switch_to_window: it also refuses to switch when an element scope is innermost (scopes.last non-nil), i.e. a within block is active. It is the internal backstop for the public switch_to_window check (session.rb:517) and covers within_window and other internal call paths, so hitting this line means a within scope was live while the internal switcher ran.
Source
Thrown at lib/capybara/session.rb:920
def _find_frame(*args, **kw_args)
case args[0]
when Capybara::Node::Element
args[0]
when String, nil
find(:frame, *args, **kw_args)
when Symbol
find(*args, **kw_args)
when Integer
idx = args[0]
all(:frame, minimum: idx + 1)[idx]
else
raise TypeError
end
end
def _switch_to_window(window = nil, **options, &window_locator)
raise Capybara::ScopeError, 'Window cannot be switched inside a `within_frame` block' if scopes.include?(:frame)
raise Capybara::ScopeError, 'Window cannot be switched inside a `within` block' unless scopes.last.nil?
if window
driver.switch_to_window(window.handle)
window
else
synchronize_windows(options) do
original_window_handle = driver.current_window_handle
begin
_switch_to_window_by_locator(&window_locator)
rescue StandardError
driver.switch_to_window(original_window_handle)
raise
end
end
end
end
def _switch_to_window_by_locatorView on GitHub (pinned to 15b5fdb76e)
Solutions
- Use the public API and move the switch outside any within block
- Use within_window(w) { ... } for window-scoped work instead of the internal switcher
- Remove monkey-patches/helpers that call page.send(:_switch_to_window, ...)
Example fix
# before
within('.results') do
page.send(:_switch_to_window, w) # Capybara::ScopeError
end
# after
switch_to_window(w)
within('.results') { click_link 'First' } Defensive patterns
Strategy: validation
Validate before calling
page.switch_to_window(w) if page.send(:scopes).last.nil? && !page.send(:scopes).include?(:frame)
Prevention
- Never call private session internals; use switch_to_window/within_window
- Keep window switches out of within blocks
When it happens
Trigger: Calling the private page.send(:_switch_to_window, w) from helper code inside a within block; monkey-patches or debugging snippets that bypass the public API's own ScopeError.
Common situations: Helper libraries invoking the private switcher directly; monkey-patched session code that reaches the internal method with an element scope still on the stack.
Related errors
- `switch_to_window` is not supposed to be invoked from `withi
- `switch_to_frame(:parent)` cannot be called from inside a de
- `switch_to_frame(:top)` cannot be called from inside a desce
- Window cannot be switched inside a `within_frame` block
- `switch_to_window` can take either a block or a window, not
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/0e4a3dfa227d261b.
Report an issue: GitHub.