grafana/k6 · error

frame not found for id

Error message

frame not found for id %s

What it means

Thrown by ElementHandle.ContentFrame()/OwnerFrame() in k6's browser module. The handle's node is described via CDP DOM.describeNode to get its FrameID, but the frame manager has no live frame registered under that ID. This means the frame owning the element was detached, destroyed, or never attached to the frame tree.

Solutions

  1. Re-acquire the iframe element handle (page.$ or page.locator) after the navigation/re-render and call contentFrame() again
  2. Wait for the page/frame to settle first: page.waitForLoadState() or page.waitForNavigation() before stepping into the iframe
  3. Verify the iframe is still connected before stepping in: const ok = await el.evaluate(e => e.isConnected && e.tagName === 'IFRAME')
  4. Locate the frame through page.frames() by URL/name instead of stepping through the element handle

Example fix

// before
const el = await page.$('iframe#widget');
const frame = await el.contentFrame(); // frame may be gone after re-render

// after
await page.waitForLoadState();
const el = await page.$('iframe#widget');
if (!el || !(await el.evaluate(e => e.isConnected))) {
  throw new Error('iframe removed from DOM; re-query the handle');
}
const frame = await el.contentFrame();
Defensive patterns

Strategy: validation

Validate before calling

// Before stepping into an iframe, confirm it is still an attached IFRAME node
const el = await page.$('iframe#widget');
const ok = el && await el.evaluate((e) => e.isConnected && e.tagName === 'IFRAME');
if (!ok) {
  throw new Error('iframe no longer attached; re-query before contentFrame()');
}
const frame = await el.contentFrame();

Try / catch

try {
  const frame = await el.contentFrame();
} catch (e) {
  if (/frame not found/.test(String(e.message))) {
    // frame was detached: re-query the element and retry once
    const fresh = await page.$('iframe#widget');
    frame = fresh ? await fresh.contentFrame() : null;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling contentFrame() on an iframe element handle after the frame navigated away, was removed from the DOM, or its out-of-process target was closed; calling it immediately after a page navigation before the new frame tree is attached; the SPA re-rendered and replaced the iframe node between acquiring the handle and stepping into it. Non-iframe elements fail earlier with 'element is not an iframe'.

Common situations: SPA frameworks (React/Vue) re-rendering and swapping iframe nodes; ad or analytics iframes removed mid-test; navigation between grabbing the handle and calling contentFrame(); cross-origin iframes whose OOPIF targets close unexpectedly.

Related errors


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

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:867

}

// ContentFrame returns the frame that contains this element.
func (h *ElementHandle) ContentFrame() (*Frame, error) {
	var (
		node *cdp.Node
		err  error
	)
	action := dom.DescribeNode().WithObjectID(h.remoteObject.ObjectID)
	if node, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {
		return nil, fmt.Errorf("getting remote node %q: %w", h.remoteObject.ObjectID, err)
	}
	if node == nil || node.FrameID == "" {
		return nil, fmt.Errorf("element is not an iframe")
	}

	frame, ok := h.frame.manager.getFrameByID(node.FrameID)
	if !ok {
		return nil, fmt.Errorf("frame not found for id %s", node.FrameID)
	}

	return frame, nil
}

// Dblclick scrolls element into view and double clicks on the element.
func (h *ElementHandle) Dblclick(opts *ElementHandleDblclickOptions) error {
	dblclick := func(_ context.Context, handle *ElementHandle, p *Position) (any, error) {
		return nil, handle.dblclick(p, opts.ToMouseClickOptions())
	}
	dblclickAction := h.newPointerAction(dblclick, &opts.ElementHandleBasePointerOptions)
	if _, err := call(h.ctx, dblclickAction, opts.Timeout); err != nil {
		return fmt.Errorf("double clicking on element: %w", err)
	}

	applySlowMo(h.ctx)

	return nil

View on GitHub (pinned to 3fcf5388d7)