grafana/k6 · error
frame has been detached 1
Error message
frame has been detached 1
What it means
Page.getFrameElement (page.go:643-655) backs frame.frameElement(). 'frame has been detached 1' is returned when f.parentFrame == nil: the frame has no parent in this page's frame tree, so it is either the main frame (which has no <iframe> element of its own) or it was detached and pruned from the tree.
Source
Thrown at internal/js/modules/k6/browser/common/page.go:653
_, err := action.Do(cdp.WithExecutor(p.ctx, p.session))
if err != nil {
return fmt.Errorf("evaluating script on document: %w", err)
}
return nil
}
func (p *Page) getFrameElement(f *Frame) (handle *ElementHandle, _ error) {
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)View on GitHub (pinned to 93accf6570)
Solutions
- Only call frameElement() on child frames, never on page.mainFrame()
- Re-list page.frames() immediately before use to get a live frame reference
- Wait for the iframe selector to be attached before resolving its frame element
- Wrap in try-catch and re-discover frames when the page mutates iframes dynamically
Example fix
// before
const frame = page.frames()[0]; // may be the main frame
const el = await frame.frameElement(); // error: no parent
// after
const frame = page.frames().find(f => f !== page.mainFrame());
if (frame) { const el = await frame.frameElement(); } Defensive patterns
Strategy: try-catch
Validate before calling
// Only ask child frames for their frame element
if (frame === page.mainFrame()) throw new Error('main frame has no frame element');
const alive = page.frames().some(f => f === frame);
if (alive) { const el = await frame.frameElement(); } Try / catch
try {
const el = await frame.frameElement();
} catch (e) {
if (String(e.message).includes('detached')) {
frame = page.frames().find(f => f.name() === wanted); // re-discover
el = await frame.frameElement();
} else { throw e; }
} Prevention
- Never call frameElement() on page.mainFrame()
- Re-list page.frames() right before use rather than caching frame references
- Confirm the iframe is still attached to the DOM before resolving its frame element
When it happens
Trigger: Calling frameElement() on the main frame; calling it on a child frame whose <iframe> was removed from the DOM between listing frames and making the call.
Common situations: Iterating page.frames() and calling frameElement() after the SPA removed the iframe; passing page.mainFrame() where a child frame was expected; frames captured at setup time and reused later.
Related errors
- frame has been detached
- 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/e2840528bc764522.
Report an issue: GitHub.