grafana/k6 · error
finding iframe with selector %q: %w
Error message
finding iframe with selector %q: %w
What it means
stepIntoFrame() resolves the iframe part of a frame-crossing selector (e.g. 'iframe >> button') by waiting for the iframe element; this error wraps that wait failing — almost always a timeout waiting for the iframe element to attach, or a strict-mode violation when several elements match.
Source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:643
return false, fmt.Errorf(
"waiting for states %v of element %q", states, reflect.TypeOf(result))
}
// stepIntoFrame steps into an iframe/frame. Due to CORS, we need to perform this
// step outside of the browser (chromium). It returns the frame that it has stepped
// into and the selector to use within that frame.
func (h *ElementHandle) stepIntoFrame(
apiCtx context.Context, parsedSelector *Selector, frameNavIndex int, opts *FrameWaitForSelectorOptions,
) (*Frame, string, error) {
// Split selector at frame navigation boundary
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
}View on GitHub (pinned to 93accf6570)
Solutions
- Increase the timeout option for the wait
- Verify the iframe part of the selector matches exactly one element
- Wait for the iframe to exist/load before querying inside it
- Prefer page.frameLocator() which re-resolves the frame chain robustly
Example fix
// before
await handle.waitForSelector('iframe >> .btn', { timeout: 1000 }); // finding iframe with selector
// after
await handle.waitForSelector('iframe >> .btn', { timeout: 30000 });
// or use the frame API:
const fl = page.frameLocator('#myframe');
await fl.locator('.btn').click(); Defensive patterns
Strategy: retry
Validate before calling
// Verify the iframe exists (and is unique) before crossing into it
const frames = await page.$$('iframe[src*="example"]');
if (frames.length !== 1) throw new Error(`expected 1 iframe, got ${frames.length}`); Try / catch
try {
await handle.waitForSelector('iframe >> .btn', { timeout: 30000 });
} catch (e) {
if (String(e).includes('finding iframe with selector')) {
await sleep(1000); // let the iframe attach, then retry
await handle.waitForSelector('iframe >> .btn', { timeout: 30000 });
} else { throw e; }
} Prevention
- Give frame-crossing queries generous timeouts
- Make iframe selectors unique — strict mode is enforced internally
- Prefer page.frameLocator() over hand-built 'iframe >> sel' strings
When it happens
Trigger: elementHandle.waitForSelector()/query with a frame-crossing selector where the iframe element does not appear within opts.Timeout, matches multiple elements (Strict is forced true here), or the wait itself errors.
Common situations: Slow-loading or dynamically injected iframes; selector matching a wrapper instead of the iframe; ad/analytics iframes appearing late; default timeout too short for heavy pages.
Related errors
- getting iframe frame: %w
- waiting for selector %q: %w
- clicking on %q: %w
- checking %q: %w
- setting checked %q: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/ee6c12b4c1c1125e.
Report an issue: GitHub.