grafana/k6 · error
finding iframe with selector
Error message
finding iframe with selector %q: %w
What it means
stepIntoFrame() resolves chained selectors that cross iframe boundaries (e.g. 'iframe#a >> button'). It waits for the iframe element itself using the selector prefix before the '>>' boundary, and that waitForSelector call failed — usually a timeout waiting for the iframe element to appear or become visible.
Solutions
- Wait for the iframe to exist/attach first: await page.locator('iframe#app').waitFor() before using the chained selector
- Verify the iframe selector actually matches: (await page.locator('iframe#app').count()) should be 1
- Increase the timeout on the action or globally (page.setDefaultTimeout / options.timeout)
- If the iframe is cross-origin, ensure it has fully loaded — prefer page.waitForLoadState('load') or frame-level waits before stepping in
Example fix
// before
await page.locator('iframe#widget >> button.go').click();
// after
await page.locator('iframe#widget').waitFor({ state: 'attached' });
await page.waitForLoadState('load');
await page.locator('iframe#widget >> button.go').click({ timeout: 30_000 }); Defensive patterns
Strategy: validation
Validate before calling
const iframeSel = 'iframe#widget';
await page.locator(iframeSel).waitFor({ state: 'attached', timeout: 15_000 });
if ((await page.locator(iframeSel).count()) !== 1) {
throw new Error(`expected exactly one iframe for ${iframeSel}`);
} Try / catch
try {
await page.locator('iframe#widget >> button').click({ timeout: 15_000 });
} catch (e) {
if (/finding iframe with selector/.test(String(e))) {
await page.waitForLoadState('load');
await page.locator('iframe#widget >> button').click({ timeout: 30_000 });
} else throw e;
} Prevention
- Wait for the iframe element to attach before using '>>' chained selectors
- Assert selector uniqueness (count === 1) before chaining into frames
- Size timeouts to when the app actually mounts iframes
When it happens
Trigger: Using a frame-crossing selector/locator where the <iframe> element does not exist yet or stays hidden within the timeout: page.locator('iframe[title="app"] >> text=Submit').click() before the iframe is injected; iframe with display:none; wrong iframe selector (no match ever); default timeout too short for slow lazy-loading.
Common situations: SPAs that mount iframes late (after auth, after data fetch); ad or widget iframes hidden until interaction; misspelled iframe selectors; slow CI machines where the default timeout expires first.
Related errors
- element is not an iframe
- an error occurred communicating with k6 Cloud
- " " does not support " " matcher
- can't query n-th element in a chained selector with capture
- checking is hidden
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/ee6c12b4c1c1125e.
Report an issue: GitHub.
Appendix: 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 3fcf5388d7)