grafana/k6 · error
element is not an iframe
Error message
element is not an iframe
What it means
ContentFrame() got a successful DescribeNode response but the node has no FrameID — by CDP semantics only iframe/frame elements carry one. k6 reports this as a plain 'element is not an iframe' error: you asked for the content frame of an element that is not a frame container.
Solutions
- Fix the selector to target the <iframe> element itself: iframe#app, iframe[title="..."], or frame,iframe
- Verify with a tagName check before stepping in: await el.evaluate((n) => n.tagName) === 'IFRAME'
- If the app swapped iframes for another mechanism, use page.frame()/waitForFrame on the actual frame URL or name instead
- For wrapper containers, chain through the iframe: 'div.widget >> iframe >> button'
Example fix
// before
const frame = await page.$('.widget-container').contentFrame();
// after
const frame = await page.$('.widget-container iframe').contentFrame(); Defensive patterns
Strategy: type-guard
Validate before calling
const el = await page.$('.widget iframe'); // selector must end at the <iframe>
if ((await el.evaluate((n) => n.tagName)) !== 'IFRAME') {
throw new Error('selector did not resolve to an iframe element');
} Type guard
async function contentFrameOf(page, selector) {
const el = await page.$(selector);
if (!el) return null;
const isIframe = (await el.evaluate((n) => n.tagName)) === 'IFRAME';
return isIframe ? await el.contentFrame() : null;
} Try / catch
try {
const frame = await el.contentFrame();
} catch (e) {
if (/element is not an iframe/.test(String(e))) {
// selector matched a wrapper; descend to the real iframe
const frame = await (await page.$('.widget iframe')).contentFrame();
} else throw e;
} Prevention
- End frame-crossing selectors at the <iframe> element itself, not a wrapper
- Verify tagName === 'IFRAME' before contentFrame() when selectors come from DevTools copies
- When apps replace iframes with portals, switch to page.frame({ name/url }) lookups
When it happens
Trigger: Calling contentFrame() on a plain element (div, span, ...), or using a frame-chained selector ('iframe >> button') where the prefix before '>>' actually matches a non-iframe node that merely wraps the real iframe; also elements inside the iframe itself being mistaken for the iframe.
Common situations: Selector matches a wrapper div around the iframe instead of the iframe; template components rendering the iframe inside a custom element; copied selectors from DevTools pointing at a container; refactor replaced the iframe with a portal/div.
Related errors
- finding iframe with selector
- getting iframe frame
- an error occurred communicating with k6 Cloud
- " " does not support " " matcher
- can't query n-th element in a chained selector with capture
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/979f5ca587e6844e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:862
return fmt.Errorf("clicking on element: %w", err)
}
applySlowMo(h.ctx)
return nil
}
// 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)View on GitHub (pinned to 3fcf5388d7)