grafana/k6 · error
element is not an iframe
Error message
element is not an iframe
What it means
ContentFrame() returns this when DOM.describeNode yields a node with no FrameID: the described node is not an iframe element. Only iframe elements own a content frame, so asking a regular element for one is a usage error.
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 93accf6570)
Solutions
- Verify the element's tag is IFRAME before calling contentFrame()
- Tighten the selector to target the <iframe> itself
- Use page.frameLocator(selector) which encodes the intent explicitly
Example fix
// before
const frame = await (await page.$('#player')).contentFrame(); // element is not an iframe
// after
const frame = await (await page.$('#player iframe')).contentFrame();
// or
const fl = page.frameLocator('#player iframe'); Defensive patterns
Strategy: type-guard
Validate before calling
const isIframe = await handle.evaluate((el) => el.tagName === 'IFRAME');
if (!isIframe) throw new Error('contentFrame requires an <iframe> element'); Type guard
async function isFrameElement(handle) {
return handle.evaluate((el) => el instanceof HTMLIFrameElement);
} Try / catch
try {
const frame = await handle.contentFrame();
} catch (e) {
if (String(e).includes('element is not an iframe')) {
// selector matched the wrong node; re-target the <iframe> itself
} else { throw e; }
} Prevention
- Point selectors at the iframe element, not its wrapper
- Use frameLocator() to express frame intent explicitly
When it happens
Trigger: handle.contentFrame() on a div/button/any non-iframe element; also frame-crossing selectors whose 'before frame' part resolves to a non-iframe node (then surfaced via 'getting iframe frame').
Common situations: Selector matches a wrapper div instead of the iframe; assuming an embedded player/widget is an iframe when it is a div/video; typos in the iframe selector.
Related errors
- predicate function is not callable
- frame has been detached 1
- frame has been detached
- "handler" argument cannot be nil
- clip area is either empty or outside the viewport
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/979f5ca587e6844e.
Report an issue: GitHub.