teamcapybara/capybara · error · Capybara::ScopeError
`switch_to_frame(:parent)` cannot be called from inside a de
Error message
`switch_to_frame(:parent)` cannot be called from inside a descendant frame's `within` block.
What it means
switch_to_frame(:parent) is only valid when the innermost scope is a frame (scopes.last == :frame). Calling it while a within block is active - even one nested inside a frame - raises Capybara::ScopeError, because popping to the parent frame would silently escape the element scope the block established.
Source
Thrown at lib/capybara/session.rb:415
# If you use this method you are responsible for making sure you switch back to the parent frame when done in the frame changed to.
# {#within_frame} is preferred over this method and should be used when possible.
# May not be supported by all drivers.
#
# @overload switch_to_frame(element)
# @param [Capybara::Node::Element] element iframe/frame element to switch to
# @overload switch_to_frame(location)
# @param [Symbol] location relative location of the frame to switch to
# * :parent - the parent frame
# * :top - the top level document
#
def switch_to_frame(frame)
case frame
when Capybara::Node::Element
driver.switch_to_frame(frame)
scopes.push(:frame)
when :parent
if scopes.last != :frame
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's " \
'`within` block.'
end
scopes.pop
driver.switch_to_frame(:parent)
when :top
idx = scopes.index(:frame)
top_level_scopes = [:frame, nil]
if idx
if scopes.slice(idx..).any? { |scope| !top_level_scopes.include?(scope) }
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's " \
'`within` block.'
end
scopes.slice!(idx..)
driver.switch_to_frame(:top)
end
else
raise ArgumentError, 'You must provide a frame element, :parent, or :top when calling switch_to_frame'
endView on GitHub (pinned to 15b5fdb76e)
Solutions
- Close the enclosing within block before calling switch_to_frame(:parent)
- Prefer the within_frame(el) { ... } block form, which returns to the parent frame automatically at block exit
- To escape all frames, exit every within block first and use switch_to_frame(:top)
Example fix
# before
within_frame(:css, 'iframe.chat') do
within('.composer') do
switch_to_frame(:parent) # Capybara::ScopeError
end
end
# after
within_frame(:css, 'iframe.chat') do
within('.composer') { fill_in 'Message', with: 'hi' }
end # frame scope restored automatically, no manual switch needed Defensive patterns
Strategy: validation
Validate before calling
switch_to_frame(:parent) if page.send(:scopes).last == :frame
Try / catch
begin
switch_to_frame(:parent)
rescue Capybara::ScopeError => e
raise "still inside a `within` block - restructure before popping frames (#{e.message})"
end Prevention
- Use within_frame's block form instead of manual switch_to_frame
- Never call switch_to_frame from inside within; end the scoped block first
When it happens
Trigger: within_frame(el) { within('.toolbar') { switch_to_frame(:parent) } } - the innermost scope is the within scope, not :frame; also any manual switch_to_frame(:parent) issued from page-object methods invoked inside a within block.
Common situations: Page objects mixing within with manual frame navigation; refactoring from the looser Capybara 1.x frame API; copy-pasting frame-navigation helpers into scoped contexts.
Related errors
- `switch_to_frame(:top)` cannot be called from inside a desce
- You must provide a frame element, :parent, or :top when call
- `switch_to_window` is not supposed to be invoked from `withi
- Window cannot be switched inside a `within_frame` block
- Window cannot be switched inside a `within` block
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/d5dc86f0b9a1d1fb.
Report an issue: GitHub.