grafana/k6 · error

parent frame has been detached

Error message

parent frame has been detached

What it means

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.

Solutions

  1. Wait for the page to settle (waitForLoadState) before querying frame elements
  2. Re-acquire the page/frame objects after navigation and retry once
  3. If the popup/target may have closed, check page.isClosed() before the call
  4. Upgrade k6 — frame session lifecycle handling around navigation has seen fixes
Defensive patterns

Strategy: retry

Validate before calling

await page.waitForLoadState('load');
if (page.isClosed()) throw new Error('page closed before frame query');
const el = await frame.frameElement();

Try / catch

try {
  await frame.frameElement();
} catch (e) {
  if (/detached/.test(e.message)) {
    await page.waitForLoadState('load');
    return frame.frameElement(); // retry once after settle
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Same family as the other detach errors: navigation races, popup close races, CI slowness widening the window between frame tree walk and session use.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/a25f5fcb9ad3c899. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/page.go:664

	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 3fcf5388d7)