{"record":{"id":"a25f5fcb9ad3c899","repo":"grafana/k6","slug":"parent-frame-has-been-detached","errorCode":null,"errorMessage":"parent frame has been detached","messagePattern":"parent frame has been detached","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/page.go","lineNumber":664,"sourceCode":"\tif f == nil {\n\t\tp.logger.Debugf(\"Page:getFrameElement\", \"sid:%v frame:nil\", p.sessionID())\n\t} else {\n\t\tp.logger.Debugf(\"Page:getFrameElement\", \"sid:%v fid:%s furl:%s\",\n\t\t\tp.sessionID(), f.ID(), f.URL())\n\t}\n\n\tparent := f.parentFrame\n\tif parent == nil {\n\t\treturn nil, errors.New(\"frame has been detached 1\")\n\t}\n\n\trootFrame := f\n\tfor ; rootFrame.parentFrame != nil; rootFrame = rootFrame.parentFrame {\n\t}\n\n\tparentSession, ok := p.getFrameSession(cdp.FrameID(rootFrame.ID()))\n\tif !ok {\n\t\treturn nil, errors.New(\"parent frame has been detached\")\n\t}\n\n\taction := dom.GetFrameOwner(cdp.FrameID(f.ID()))\n\tbackendNodeID, _, err := action.Do(cdp.WithExecutor(p.ctx, parentSession.session))\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"frame with the given id was not found\") {\n\t\t\treturn nil, errors.New(\"frame has been detached\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"getting frame owner: %w\", err)\n\t}\n\n\tparent = f.parentFrame\n\tif parent == nil {\n\t\treturn nil, errors.New(\"frame has been detached 2\")\n\t}\n\treturn parent.adoptBackendNodeID(mainWorld, backendNodeID)\n}\n","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/grafana/k6/blob/3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee/internal/js/modules/k6/browser/common/page.go#L646-L682","documentation":"Same getFrameElement flow (page.go:655-663): after walking to the root frame, k6 looks up the frame session for that root via p.getFrameSession. If no session is registered for the root frame id, the root's CDP session is gone (navigation swapped page sessions, or the target closed), so the DOM query for the frame owner cannot be executed.","triggerScenarios":"frameElement() racing a top-level navigation that replaces the page session; the root target/page being closed while the call is in flight; an out-of-process iframe whose session has not been (re)attached.","commonSituations":"Same family as the other detach errors: navigation races, popup close races, CI slowness widening the window between frame tree walk and session use.","solutions":["Wait for the page to settle (waitForLoadState) before querying frame elements","Re-acquire the page/frame objects after navigation and retry once","If the popup/target may have closed, check page.isClosed() before the call","Upgrade k6 — frame session lifecycle handling around navigation has seen fixes"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"await page.waitForLoadState('load');\nif (page.isClosed()) throw new Error('page closed before frame query');\nconst el = await frame.frameElement();","typeGuard":null,"tryCatchPattern":"try {\n  await frame.frameElement();\n} catch (e) {\n  if (/detached/.test(e.message)) {\n    await page.waitForLoadState('load');\n    return frame.frameElement(); // retry once after settle\n  }\n  throw e;\n}","preventionTips":["Check page.isClosed() before frame queries on popups","Do not run frame operations mid-navigation; wait for load state","Upgrade k6 for session lifecycle fixes around navigation"],"tags":["browser","iframe","frame","cdp-session"],"backgroundTag":"frame-detached","analyzedSha":"3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}