{"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/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L607-L643","documentation":"waitForElementStates expects 'done', a bool, or an 'error:...' string from the injected script. Any other type produces this error. The message also misuses %q with a reflect.Type argument, so it renders like waiting for states [visible] of element %!q(*reflect.rtype=...). This wait backs every actionability check and the Is* helpers (isVisible, isChecked, ...).","triggerScenarios":"Any element action (click, fill via its visible/enabled/editable preconditions) or isVisible()/isHidden()/isChecked()-style checks when the eval returns an unexpected type — typically the execution context was destroyed mid-wait or the injected script mismatches the binary.","commonSituations":"Page navigating while an action waits for actionability; custom xk6 builds with stale injected script; rare races right at timeout expiry.","solutions":["Retry the action after the page settles and the element is re-located","Upgrade to a clean matching k6 build","Increase the timeout so waits don't race navigation","Report with a minimal script if reproducible on a stock release"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await handle.click();\n} catch (e) {\n  if (String(e).includes('waiting for states')) {\n    await (await page.waitForSelector(sel, { state: 'visible' })).click();\n  } else { throw e; }\n}","preventionTips":["Expect this from any Is*() helper and action prechecks","Avoid actions that race navigation","Keep k6 versions matched"],"tags":["browser","actionability","wait","injected-script"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}