grafana/k6 · error
frame has been detached
Error message
frame has been detached
What it means
In getFrameElement (page.go:665-672) k6 issues CDP DOM.getFrameOwner to find which DOM node owns the frame. The call failed and the CDP error string contained 'frame with the given id was not found' — the browser had already removed this frame from its frame tree while k6 was asking for its owner, so k6 maps it to 'frame has been detached'.
Solutions
- Re-check page.frames() and retry frameElement() on a frame that is still listed
- Wait for the iframe to be stably present (waitForSelector on the iframe element) before querying frameElement
- Query iframe content via frame.waitForSelector instead of resolving the frame element
- Guard the call with try-catch and treat this message as 'frame gone, re-acquire'
Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the frame still exists in the tree before asking for its element
const stillThere = page.frames().some(fr => fr.id === frame.id);
if (!stillThere) throw new Error('frame removed; re-acquire');
await frame.frameElement(); Try / catch
try {
await frame.frameElement();
} catch (e) {
if (/frame has been detached/.test(e.message)) {
return null; // frame removed mid-call — treat as absent
}
throw e;
} Prevention
- Wait for the iframe element to be attached and stable before frameElement()
- Prefer querying frame content (waitForSelector) over resolving the frame element
- Do not poll frame properties in a loop while the page unloads
When it happens
Trigger: frameElement() racing frame removal: the iframe is deleted by page script, the page navigates away, or the frame tree is rebuilt, all between k6's tree walk and the CDP round-trip.
Common situations: Dynamic iframes (ads, embeds, editors) destroyed on a timer; scripts removing iframes right after content loads; assertions on iframes that the WuT intentionally tears down.
Related errors
- Error while parsing selector
- frame has been detached 1
- frame has been detached 2
- frame not found for id
- creating a new
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/677421acb35b42b5.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/page.go:671
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 3fcf5388d7)