{"record":{"id":"cb70d16eba359dfd","repo":"grafana/k6","slug":"waiting-for-selector-q-w-cb70d1","errorCode":null,"errorMessage":"waiting for selector %q: %w","messagePattern":"waiting for selector %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":2197,"sourceCode":"\t\t\te := &k6ext.UserFriendlyError{\n\t\t\t\tErr:     err,\n\t\t\t\tTimeout: opts.Timeout,\n\t\t\t}\n\t\t\tif opts.URL != \"\" {\n\t\t\t\treturn fmt.Errorf(\"waiting for navigation to URL matching %q: %w\", opts.URL, e)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"waiting for navigation: %w\", e)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// WaitForSelector waits for the given selector to match the waiting criteria.\nfunc (f *Frame) WaitForSelector(selector string, popts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\thandle, err := f.waitForSelectorRetry(selector, popts, maxRetry)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for selector %q: %w\", selector, err)\n\t}\n\n\treturn handle, nil\n}\n\n// WaitForTimeout waits the specified amount of milliseconds.\nfunc (f *Frame) WaitForTimeout(timeout int64) {\n\tto := time.Duration(timeout) * time.Millisecond\n\n\tf.log.Debugf(\"Frame:WaitForTimeout\", \"fid:%s furl:%q timeout:%s\", f.ID(), f.URL(), to)\n\tdefer f.log.Debugf(\"Frame:WaitForTimeout:return\", \"fid:%s furl:%q timeout:%s\", f.ID(), f.URL(), to)\n\n\tselect {\n\tcase <-f.ctx.Done():\n\tcase <-time.After(to):\n\t}\n}\n","sourceCodeStart":2179,"sourceCodeEnd":2215,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L2179-L2215","documentation":"Thrown by Frame.WaitForSelector when waitForSelectorRetry (retried up to maxRetry = 1, so essentially one attempt plus one retry) fails. The wrapped error is usually a timeout ('timeout ... exceeded' from the action loop), a strict-mode violation (multiple matches), or an invalid selector. This is the single most common k6 browser error: the selector never satisfied the wait state within the timeout.","triggerScenarios":"page.waitForSelector(sel) where the element never attaches; selector matches nothing because the app rendered a different DOM; strict: true (default in modern k6) with multiple matches; selector syntax error; frame detached while waiting.","commonSituations":"Selectors recorded from a different environment/build of the app; waiting for elements behind authentication when the login step failed silently; CI timing — element appears later than the default 30s timeout; iframes requiring frame.waitForSelector instead of page-level waits.","solutions":["Verify the selector in browser DevTools on the exact page state: document.querySelectorAll(sel).length should be >= 1","Increase timeout: page.waitForSelector(sel, { timeout: 60000 })","If multiple elements match, make the selector unique or pass strict: false","Confirm you are querying the right frame — for iframes get the frame first and wait on it"],"exampleFix":"// before\npage.waitForSelector('.order-row'); // 0 matches, times out at 30s\n\n// after\npage.waitForSelector('#orders .order-row:first-child', { timeout: 60_000, state: 'attached' });","handlingStrategy":"validation","validationCode":"const n = await page.evaluate((s) => document.querySelectorAll(s).length, sel);\nif (n === 0) throw new Error(`selector ${sel} matches nothing; fix before waiting`);\nif (n > 1) throw new Error(`selector ${sel} matches ${n} nodes; strict mode will fail`);","typeGuard":"function isSelectorTimeout(e) {\n  return e instanceof Error && /waiting for selector/.test(e.message);\n}","tryCatchPattern":"try {\n  await page.waitForSelector(sel, { timeout: 60_000 });\n} catch (e) {\n  if (isSelectorTimeout(e)) { /* assert why: auth failure? route not reached? */ }\n  throw e;\n}","preventionTips":["Prefer data-test attributes over generated CSS selectors","Use unique selectors and explicit timeouts","Confirm login/auth steps succeeded before waiting for gated content"],"tags":["browser","wait-for-selector","timeout","selector","strict-mode"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}