{"record":{"id":"7264e7868d8fbd75","repo":"grafana/k6","slug":"removing-child-frames-recursively-w","errorCode":null,"errorMessage":"removing child frames recursively: %w","messagePattern":"removing child frames recursively: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame_manager.go","lineNumber":269,"sourceCode":"\t\t// isn't a bug in chrome, and seems to be intended behavior. Instead\n\t\t// of worrying about the nil frame and causing the test to fail when\n\t\t// the frame is nil, we can instead return early. The frame will\n\t\t// be initialized when getFrameTree CDP request is made, which will\n\t\t// call onFrameAttached and onFrameNavigated.\n\n\t\treturn nil\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameNavigated:removeFrames\",\n\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\tif frame != nil {\n\t\tm.framesMu.Unlock()\n\t\tfor _, child := range frame.ChildFrames() {\n\t\t\tif err := m.removeFramesRecursively(child); err != nil {\n\t\t\t\tm.framesMu.Lock()\n\t\t\t\treturn fmt.Errorf(\"removing child frames recursively: %w\", err)\n\t\t\t}\n\t\t}\n\t\tm.framesMu.Lock()\n\t}\n\n\tvar mainFrame *Frame\n\tif isMainFrame && frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigated:MainFrame:initialMainFrameNavigation\",\n\t\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\t\t// Initial main frame navigation.\n\t\tframe = NewFrame(m.ctx, m, nil, frameID, m.logger)\n\t\tmainFrame = frame\n\t} else if isMainFrame && frame.ID() != string(frameID) {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigated:MainFrame:delete\",\n\t\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t oldfid:%v\",\n\t\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial, frame.ID())","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame_manager.go#L251-L287","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\npage.goto('https://example.com'); // not awaited\npage.goto('https://example.com/other'); // racing navigations\n\n// after\nawait page.goto('https://example.com');\nawait page.goto('https://example.com/other');","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isFrameCleanupError(e) {\n  return e instanceof Error && /removing (child )?frames? recursively/.test(e.message);\n}","tryCatchPattern":"try {\n  await page.goto(url);\n} catch (e) {\n  if (isFrameCleanupError(e)) { return await page.goto(url); } // one retry; race is transient\n  throw e;\n}","preventionTips":["Serialize navigations — await each goto before the next","Upgrade k6 for frame-tree race fixes","Block churning third-party frames when possible"],"tags":["browser","frame-manager","navigation","race","iframe"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}