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
- Re-acquire the iframe element handle (page.$ or page.locator) after the navigation/re-render and call contentFrame() again
- Wait for the page/frame to settle first: page.waitForLoadState() or page.waitForNavigation() before stepping into the iframe
- Verify the iframe is still connected before stepping in: const ok = await el.evaluate(e => e.isConnected && e.tagName === 'IFRAME')
- 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
- Never cache iframe element handles across navigations or re-renders
- Wait for page.waitForLoadState() before stepping into frames
- Prefer page.frames() lookup by URL/name over traversing element handles when the frame is long-lived
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
- Error while parsing selector
- frame has been detached
- getting remote node
- Unexpected end of selector while parsing selector
- an error occurred communicating with k6 Cloud
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 nilView on GitHub (pinned to 3fcf5388d7)