grafana/k6 · error

frame has been detached 1

Error message

frame has been detached 1

What it means

Page.getFrameElement (page.go:643-653) resolves the <iframe>/<frame> DOM element that owns a frame (used by frame.frameElement()). It first needs the frame's parent; if parentFrame == nil the frame either is the main frame or has been detached, so there is no parent in which to look for the frame element.

Solutions

  1. Never call frameElement() on the main frame — it has no owner element by definition
  2. Re-fetch frames from page.frames() after each navigation and use those fresh references
  3. Before calling, confirm the frame is still live (its id still appears in page.frames())
  4. Wrap in try-catch and re-acquire the frame on failure; a detached frame never comes back

Example fix

// before
const el = await page.frames()[0].frameElement(); // may be detached

// after
const frames = page.frames();
const live = frames.find(f => f.name() === 'chart');
if (live) { const el = await live.frameElement(); }
Defensive patterns

Strategy: validation

Validate before calling

// Skip the main frame and confirm the frame is still listed
const f = page.frames().find(fr => fr.name() === 'widget');
if (f) {
  const el = await f.frameElement();
} else {
  // frame gone — re-acquire or skip
}

Try / catch

try {
  handle = await frame.frameElement();
} catch (e) {
  if (/detached/.test(e.message)) {
    const fresh = page.frames().find(fr => fr.name() === 'widget');
    handle = fresh ? await fresh.frameElement() : null;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling page.mainFrame().frameElement() (main frame has no parent); calling frameElement() on an iframe frame that was removed from the DOM by navigation or script while you still held the reference.

Common situations: Iterating page.frames() while navigation adds/removes iframes; holding frame references across page.goto; ad or embed iframes deleted by their own scripts.

Related errors


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

Appendix: source

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

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