grafana/k6 · error
removing child frames recursively: %w
Error message
removing child frames recursively: %w
What it means
Thrown in FrameManager.frameNavigated while pruning the navigated frame's child frames before installing the new document: one of the recursive removeFramesRecursively calls failed and the error is re-wrapped with this prefix. The root cause is almost always the same as error 837 — Frame.detach() failing (usually disposing the document handle or stopping frame sessions) while the frame tree is being rebuilt during navigation.
Source
Thrown at internal/js/modules/k6/browser/common/frame_manager.go:269
// isn't a bug in chrome, and seems to be intended behavior. Instead
// of worrying about the nil frame and causing the test to fail when
// the frame is nil, we can instead return early. The frame will
// be initialized when getFrameTree CDP request is made, which will
// call onFrameAttached and onFrameNavigated.
return nil
}
m.logger.Debugf("FrameManager:frameNavigated:removeFrames",
"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t",
m.ID(), frameID, parentFrameID, documentID, name, url, initial)
if frame != nil {
m.framesMu.Unlock()
for _, child := range frame.ChildFrames() {
if err := m.removeFramesRecursively(child); err != nil {
m.framesMu.Lock()
return fmt.Errorf("removing child frames recursively: %w", err)
}
}
m.framesMu.Lock()
}
var mainFrame *Frame
if isMainFrame && frame == nil {
m.logger.Debugf("FrameManager:frameNavigated:MainFrame:initialMainFrameNavigation",
"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t",
m.ID(), frameID, parentFrameID, documentID, name, url, initial)
// Initial main frame navigation.
frame = NewFrame(m.ctx, m, nil, frameID, m.logger)
mainFrame = frame
} else if isMainFrame && frame.ID() != string(frameID) {
m.logger.Debugf("FrameManager:frameNavigated:MainFrame:delete",
"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t oldfid:%v",
m.ID(), frameID, parentFrameID, documentID, name, url, initial, frame.ID())View on GitHub (pinned to 93accf6570)
Solutions
- Upgrade k6 — the frame manager/negotiation code saw substantial race fixes
- Sequence operations: fully await one goto before triggering the next navigation or close
- If intermittent on an ad-heavy page, consider blocking ad/frame hosts to reduce tree churn
Example fix
// before
page.goto('https://example.com'); // not awaited
page.goto('https://example.com/other'); // racing navigations
// after
await page.goto('https://example.com');
await page.goto('https://example.com/other'); Defensive patterns
Strategy: retry
Type guard
function isFrameCleanupError(e) {
return e instanceof Error && /removing (child )?frames? recursively/.test(e.message);
} Try / catch
try {
await page.goto(url);
} catch (e) {
if (isFrameCleanupError(e)) { return await page.goto(url); } // one retry; race is transient
throw e;
} Prevention
- Serialize navigations — await each goto before the next
- Upgrade k6 for frame-tree race fixes
- Block churning third-party frames when possible
When it happens
Trigger: A page with iframes navigating while a child frame's CDP session/context is concurrently being torn down; navigation racing page.close(); browser-initiated frame detach (ad iframe removed) colliding with the k6-side cleanup.
Common situations: Ad-heavy or iframe-heavy sites under load; scripts that navigate and close pages in quick succession; older k6 browser versions with frame-tree races (this area was rewritten in later k6 releases).
Related errors
- removing frames recursively: %w
- execution context %q not found
- missing required argument 'url'
- can't fetch the page for unknown reason
- errorText
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/7264e7868d8fbd75.
Report an issue: GitHub.