{"record":{"id":"63985052a143c6a1","repo":"grafana/k6","slug":"waiting-for-states-v-of-element-q","errorCode":null,"errorMessage":"waiting for states %v of element %q","messagePattern":"waiting for states (.+?) of element %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":625,"sourceCode":"\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn, states, timeout.Milliseconds())\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\tswitch v := result.(type) {\n\tcase string: // Either we're done or an error happened (returned as \"error:...\" from JS)\n\t\tif v == resultDone {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, errorFromDOMError(v)\n\tcase bool:\n\t\treturn v, nil\n\t}\n\n\treturn false, fmt.Errorf(\n\t\t\"waiting for states %v of element %q\", states, reflect.TypeOf(result))\n}\n\n// stepIntoFrame steps into an iframe/frame. Due to CORS, we need to perform this\n// step outside of the browser (chromium). It returns the frame that it has stepped\n// into and the selector to use within that frame.\nfunc (h *ElementHandle) stepIntoFrame(\n\tapiCtx context.Context, parsedSelector *Selector, frameNavIndex int, opts *FrameWaitForSelectorOptions,\n) (*Frame, string, error) {\n\t// Split selector at frame navigation boundary\n\tbeforeFrame, afterFrame := h.splitSelectorAtFrame(parsedSelector, frameNavIndex)\n\n\t// Find the iframe element using the \"before frame\" selector\n\tiframeSelector := h.reconstructSelector(beforeFrame)\n\n\tiframeHandle, err := h.waitForSelector(apiCtx, iframeSelector, opts)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"finding iframe with selector %q: %w\", iframeSelector, err)","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/grafana/k6/blob/3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee/internal/js/modules/k6/browser/common/element_handle.go#L607-L643","documentation":"waitForElementStates() (the engine behind el.waitFor({state:...}) and actionability waits) evaluated its injected script but the result was neither a string ('done'/'error:...' protocol) nor a bool. This is an internal contract violation between the injected JS and the Go side, not a wait timeout — timeouts surface as ErrTimedOut.","triggerScenarios":"Waiting for any element state where the evaluation returns an unexpected type: page-side tampering with the injected script's environment, or a k6 internal regression; all normal states (visible, hidden, enabled, disabled, editable) produce bool or string results.","commonSituations":"Hostile pages overriding primitives; k6 version skew after upgrades; essentially unreproducible on well-behaved pages.","solutions":["Upgrade k6 to the latest version to clear internal regressions","Reproduce on a static page; if clean there, audit the app for scripts that patch built-ins","Replace the state wait with a polling loop on isVisible()/isEnabled() as a workaround","Report a k6 issue with selector, states, and k6 version"],"exampleFix":"// workaround polling\n// before\nawait el.waitFor({ state: 'visible' });\n\n// after\nlet ok = false;\nfor (let i = 0; i < 50 && !ok; i++) {\n  ok = await el.isVisible();\n  if (!ok) await page.waitForTimeout(200);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await el.waitFor({ state: 'visible' });\n} catch (e) {\n  if (/waiting for states/.test(String(e))) {\n    for (let i = 0; i < 50 && !(await el.isVisible()); i++) {\n      await page.waitForTimeout(200);\n    }\n  } else throw e;\n}","preventionTips":["Keep k6 version pinned and updated in lockstep","Suspect page-side script interference when invariant errors appear only on one app"],"tags":["browser","wait","internal","js-evaluation","invariant"],"backgroundTag":"browser-unexpected-eval-result","analyzedSha":"3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}