grafana/k6 · error

getting iframe frame

Error message

getting iframe frame: %w

What it means

After stepIntoFrame() successfully found the iframe element, calling ContentFrame() on its handle failed. ContentFrame performs a CDP dom.DescribeNode and maps the node's FrameID to a known frame; the wrapped error is either the DescribeNode CDP failure, 'element is not an iframe', or 'frame not found for id ...' (the frame is not yet registered with the frame manager).

Solutions

  1. Confirm the selector matches a real <iframe> element: tagName check via evaluate
  2. Wait for the frame to be registered: page.waitForFrame({ url/name }) or wait for a known element inside the frame before chaining
  3. Retry once after a short delay — registration races clear once loading completes
  4. Use the frame API directly (page.frame({ name }) / frameLocator) instead of chained '>>' selectors for dynamically-swapped iframes

Example fix

// before
await page.locator('iframe#widget >> button').click();

// after
await page.waitForFrame({ name: 'widget' });
const frame = page.frame({ name: 'widget' });
await frame.locator('button').click();
Defensive patterns

Strategy: validation

Validate before calling

const el = await page.$('iframe#widget');
const tag = await el.evaluate((n) => n.tagName);
if (tag !== 'IFRAME') throw new Error(`selector matched <${tag}>, not an iframe`);

Type guard

async function isIframeHandle(el) {
  return (await el.evaluate((n) => n.tagName)) === 'IFRAME';
}

Try / catch

try {
  const frame = await el.contentFrame();
} catch (e) {
  if (/getting iframe frame/.test(String(e))) {
    await page.waitForFrame({ url: /widget/ });
    const frame = await (await page.$('iframe#widget')).contentFrame();
  } else throw e;
}

Prevention

When it happens

Trigger: Chained frame-crossing selectors where the found element is not actually an iframe, the iframe's content frame hasn't been attached/registered yet (still loading or about:blank swap), or the CDP session target is gone; races where the iframe navigates between being found and described.

Common situations: Selectors matching a div that looks like an iframe wrapper; same-origin iframes still initializing; dynamic iframe src swaps (OAuth popup-style flows embedded inline); pages destroying/recreating iframes during load.

Related errors


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

Appendix: source

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

	beforeFrame, afterFrame := h.splitSelectorAtFrame(parsedSelector, frameNavIndex)

	// Find the iframe element using the "before frame" selector
	iframeSelector := h.reconstructSelector(beforeFrame)

	iframeHandle, err := h.waitForSelector(apiCtx, iframeSelector, opts)
	if err != nil {
		return nil, "", fmt.Errorf("finding iframe with selector %q: %w", iframeSelector, err)
	}

	// This is a valid response from waitForSelector. It means that the element
	// was either hidden or detached.
	if iframeHandle == nil {
		return nil, "", ErrElementNotVisible
	}

	frame, err := iframeHandle.ContentFrame()
	if err != nil {
		return nil, "", fmt.Errorf("getting iframe frame: %w", err)
	}

	// Wait for selector in the iframe using the "after frame" selector
	afterFrameSelector := h.reconstructSelector(afterFrame)

	return frame, afterFrameSelector, nil
}

func (h *ElementHandle) waitForSelector(
	apiCtx context.Context, selector string, opts *FrameWaitForSelectorOptions,
) (*ElementHandle, error) {
	parsedSelector, err := NewSelector(selector)
	if err != nil {
		return nil, err
	}

	// Check for frame navigation in the selector
	frameNavIndex := h.findFrameNavigationIndex(parsedSelector)

View on GitHub (pinned to 3fcf5388d7)