grafana/k6 · error
parent frame has been detached
Error message
parent frame has been detached
What it means
In Page.getFrameElement, after walking to the root frame, k6 needs the CDP session of that root frame's target. If p.getFrameSession(rootFrame.ID()) finds none (page.go:658-664), the target/session is already gone and the frame tree is unreachable — reported as 'parent frame has been detached'.
Source
Thrown at internal/js/modules/k6/browser/common/page.go:662
if f == nil {
p.logger.Debugf("Page:getFrameElement", "sid:%v frame:nil", p.sessionID())
} else {
p.logger.Debugf("Page:getFrameElement", "sid:%v fid:%s furl:%s",
p.sessionID(), f.ID(), f.URL())
}
parent := f.parentFrame
if parent == nil {
return nil, errors.New("frame has been detached 1")
}
rootFrame := f
for ; rootFrame.parentFrame != nil; rootFrame = rootFrame.parentFrame {
}
parentSession, ok := p.getFrameSession(cdp.FrameID(rootFrame.ID()))
if !ok {
return nil, errors.New("parent frame has been detached")
}
action := dom.GetFrameOwner(cdp.FrameID(f.ID()))
backendNodeID, _, err := action.Do(cdp.WithExecutor(p.ctx, parentSession.session))
if err != nil {
if strings.Contains(err.Error(), "frame with the given id was not found") {
return nil, errors.New("frame has been detached")
}
return nil, fmt.Errorf("getting frame owner: %w", err)
}
parent = f.parentFrame
if parent == nil {
return nil, errors.New("frame has been detached 2")
}
return parent.adoptBackendNodeID(mainWorld, backendNodeID)
}
View on GitHub (pinned to 93accf6570)
Solutions
- Ensure the owning page and browser context are still open before calling frameElement()
- Re-acquire the page and frames from a live context instead of reusing references from a previous iteration
- Don't call context.close() while frame operations are pending
- Retry frame discovery if the page is expected to recover
Example fix
// before const page = pages[i]; await context.close(); const el = await page.frames()[1].frameElement(); // session gone // after const el = await page.frames()[1].frameElement(); await context.close(); // close only after frame work finishes
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the page is live before frame queries
const frames = page.frames(); // throws/empty if page or context is gone
if (frames.length > 1) { const el = await frames[1].frameElement(); } Try / catch
try {
const el = await frame.frameElement();
} catch (e) {
if (String(e.message).includes('parent frame has been detached')) {
// page/target closed or crashing: re-acquire page + frame from a live context
page = await context.newPage(); await page.goto(url);
} else { throw e; }
} Prevention
- Keep the browser context open until all frame work finishes
- Don't close pages/contexts while frame operations are in flight
- Re-acquire pages and frames per iteration instead of reusing closed references
When it happens
Trigger: The page or out-of-process iframe target was closed or crashed before frameElement() ran; the browser context is being torn down (context.close()) while frame queries are in flight; cross-origin iframe processes destroyed.
Common situations: Racing page.close()/context.close() with pending frame operations; renderer crashes under load; scripts that keep frame references across iterations after the page was closed.
Related errors
- disposing document element while getting owner frame: %w
- getting document element: nil document
- waitFor retry threshold reached
- frame has been detached 2
- attaching new page: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/a25f5fcb9ad3c899.
Report an issue: GitHub.