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_locator

View on GitHub (pinned to 15b5fdb76e)

Solutions

  1. Use the public API and move the switch outside any within block
  2. Use within_window(w) { ... } for window-scoped work instead of the internal switcher
  3. 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

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


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