grafana/k6 · error
frame has been detached
Error message
frame has been detached
What it means
Page.getFrameElement calls dom.GetFrameOwner to find the <iframe>'s backend node in the parent. When CDP answers 'frame with the given id was not found' (page.go:665-671), the frame was already removed from the DOM, so k6 maps it to 'frame has been detached'.
Source
Thrown at internal/js/modules/k6/browser/common/page.go:669
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)
}
func (p *Page) getOwnerFrame(apiCtx context.Context, h *ElementHandle) (cdp.FrameID, error) {
p.logger.Debugf("Page:getOwnerFrame", "sid:%v", p.sessionID())
// document.documentElement has frameId of the owner frame
pageFn := `
node => {
const doc = node;View on GitHub (pinned to 93accf6570)
Solutions
- Re-discover the frame from page.frames() immediately before calling frameElement()
- Wait for the iframe selector (e.g. page.waitForSelector('iframe#widget')) to be attached first
- Retry the discover+frameElement sequence when the app frequently re-creates iframes
- If the iframe is gone for good, skip the step instead of retrying forever
Example fix
// before
const frame = savedFrame; // captured before a re-render
const el = await frame.frameElement(); // CDP: frame not found
// after
await page.waitForSelector('iframe#widget');
const frame = page.frames().find(f => f.url().includes('widget'));
const el = await frame.frameElement(); Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the iframe exists in the DOM before using its frame
await page.waitForSelector('iframe#widget', { state: 'attached' });
const frame = page.frames().find(f => f.url().includes('widget'));
if (frame) { const el = await frame.frameElement(); } Try / catch
try {
const el = await frame.frameElement();
} catch (e) {
if (String(e.message).includes('frame has been detached')) {
await page.waitForSelector('iframe#widget', { state: 'attached' });
frame = page.frames().find(f => f.url().includes('widget'));
el = await frame.frameElement();
} else { throw e; }
} Prevention
- Wait for the iframe selector to be attached before resolving frame elements
- Re-discover frames from page.frames() instead of caching them across re-renders
- Skip gracefully when the iframe was intentionally removed by the app
When it happens
Trigger: The <iframe> element was deleted from the DOM (SPA unmounted it) before or during frameElement(); the frame navigated away and was destroyed between discovery and the CDP call.
Common situations: Dynamic iframe mounting/unmounting in single-page apps; frame handles captured earlier and used after the page re-rendered; modals that embed iframes being dismissed.
Related errors
- frame has been detached 1
- no frame found for id %s
- finding position in frame: %w
- missing required argument 'altText'
- missing required argument 'label'
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/677421acb35b42b5.
Report an issue: GitHub.