{"record":{"id":"1472e21eea3ad448","repo":"grafana/k6","slug":"parsing-wait-for-selector-q-options-w","errorCode":null,"errorMessage":"parsing wait for selector %q options: %w","messagePattern":"parsing wait for selector %q options: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/frame_mapping.go","lineNumber":459,"sourceCode":"\t\t\t}), nil\n\t\t},\n\t\t\"waitForLoadState\": func(state string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseFrameWaitForLoadStateOptions(rt, opts, f.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForLoadState %q options: %w\", state, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.WaitForLoadState(state, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForNavigation\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForNavigation(rt, vu, f, opts)\n\t\t},\n\t\t\"waitForSelector\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseFrameWaitForSelectorOptions(rt, opts, f.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for selector %q options: %w\", selector, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\teh, err := f.WaitForSelector(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapElementHandle(vu, eh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForTimeout\": func(timeout int64) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tf.WaitForTimeout(timeout)\n\t\t\t\treturn nil, nil\n\t\t\t})\n\t\t},\n\t\t\"waitForURL\": func(url sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForURL(rt, vu, f, url, opts)","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/grafana/k6/blob/8d06114777191d21ef885d05c5f8aa9e1ed838ae/internal/js/modules/k6/browser/browser/frame_mapping.go#L441-L477","documentation":"Thrown while parsing the options object of frame.waitForSelector(selector, options) (browser/frame_mapping.go:461); the selector is echoed via %q. FrameWaitForSelectorOptions.Parse has a hard enum check on state and fails with '\"%s\" is not a valid DOM state' unless state is exactly one of attached, detached, visible or hidden (common/frame.go domElementStateToID). strict and timeout are coerced and cannot fail.","triggerScenarios":"frame.waitForSelector('#el', { state: 'Visible' }) (wrong casing); { state: 'attached ' } (trailing whitespace); { state: 'displayed' } or 'present' (invented states); state loaded from config with stray characters.","commonSituations":"Autocomplete-free editors letting casing typos through; translating Selenium expectations (displayed/present) into Playwright-style states; values arriving from CSV/JSON data sources without trimming.","solutions":["Use one of the four lowercase states: attached | detached | visible | hidden","Trim and lowercase dynamic values: state: String(raw).trim().toLowerCase() after validating against the whitelist","Omit state (defaults to visible)","Add an early assertion in your script when state comes from external data"],"exampleFix":"// before\nframe.waitForSelector('#el', { state: 'Visible' });\n// after\nframe.waitForSelector('#el', { state: 'visible' });","handlingStrategy":"validation","validationCode":"const DOM_STATES = ['attached', 'detached', 'visible', 'hidden'];\nif (opts?.state !== undefined && !DOM_STATES.includes(opts.state)) {\n  throw new Error(`state must be one of ${DOM_STATES.join('|')}, got '${opts.state}'`);\n}","typeGuard":"function isWaitForSelectorOptions(o) {\n  if (o == null) return true;\n  return (o.state === undefined || ['attached', 'detached', 'visible', 'hidden'].includes(o.state)) &&\n    (o.timeout === undefined || typeof o.timeout === 'number');\n}","tryCatchPattern":"try { const h = await frame.waitForSelector(sel, opts); } catch (e) { if (!String(e.message).includes('is not a valid DOM state')) throw e; }","preventionTips":["Whitelist the four DOM states in a shared constant and validate data-driven values","Prefer waitForSelector(sel, { state: 'hidden' }) semantics over inventing states like 'gone'","Trim external strings before using them as enum values"],"tags":["k6","k6-browser","frame","wait-for-selector","dom-state","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"8d06114777191d21ef885d05c5f8aa9e1ed838ae","analyzedAt":"2026-09-14T20:10:14.619Z","contentChangedAt":"2026-09-14T20:10:14.619Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}