{"record":{"id":"d2c688106843db4b","repo":"grafana/k6","slug":"waiting-for-element-state-q-w","errorCode":null,"errorMessage":"waiting for element state %q: %w","messagePattern":"waiting for element state %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":1572,"sourceCode":"\t\treturn nil, handle.typ(apiCtx, text, KeyboardOptions{})\n\t}\n\ttypeAction := h.newAction(\n\t\t[]string{}, typ, false, withRetry, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, typeAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"typing text %q: %w\", text, err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// WaitForElementState waits for the element to reach the given state.\nfunc (h *ElementHandle) WaitForElementState(state string, opts *ElementHandleWaitForElementStateOptions) error {\n\t_, err := h.waitForElementState(h.ctx, []string{state}, opts.Timeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"waiting for element state %q: %w\", state, err)\n\t}\n\n\treturn nil\n}\n\n// WaitForSelector waits for the selector to appear in the DOM.\nfunc (h *ElementHandle) WaitForSelector(selector string, opts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\thandle, err := h.waitForSelector(h.ctx, selector, opts)\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// evalWithScript evaluates the given js code in the scope of this ElementHandle and returns the result.\n// The js code can call helper functions from injected_script.js.\nfunc (h *ElementHandle) evalWithScript(","sourceCodeStart":1554,"sourceCodeEnd":1590,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L1554-L1590","documentation":"Wrapped failure from the public ElementHandle.WaitForElementState (elementHandle.waitForElementState(state)). The inner waitForElementState runs the injected waitForElementStates script with [state]; it fails when the element never reaches the state within opts.Timeout (mapped to ErrTimedOut via 'timed out' detection), when the state string is not one the injected script knows, or when the element is detached/not an element.","triggerScenarios":"Waiting for 'visible' on an element that stays hidden until timeout; waiting for 'stable' on an infinitely animating element; passing an unsupported state string; waiting on a handle whose node was removed from the DOM.","commonSituations":"Spinners and skeletons that never resolve on failed backend calls; elements toggled by CSS transitions; waiting for 'enabled' on buttons gated by async form validation; states confused with waitForSelector states like 'attached'.","solutions":["Increase opts.Timeout: el.waitForElementState('visible', { timeout: '60s' })","Use a supported state: visible, hidden, stable, enabled, editable (attached/detached belong to waitForSelector)","If the underlying app is stuck (backend error), fix or stub that dependency instead of lengthening waits","For 'hidden' waits on elements that may already be gone, tolerate detachment by catching and checking the element still exists"],"exampleFix":"// before\nel.waitForElementState('attached', { timeout: '5s' }); // invalid state for this API\n\n// after\nel.waitForElementState('visible', { timeout: '30s' });","handlingStrategy":"validation","validationCode":"const VALID_STATES = ['visible', 'hidden', 'stable', 'enabled', 'editable'];\nfunction assertValidState(state) {\n  if (!VALID_STATES.includes(state)) {\n    throw new Error(`invalid element state ${state}; expected one of ${VALID_STATES.join(', ')}`);\n  }\n}\nassertValidState(state);\nel.waitForElementState(state, { timeout: '30s' });","typeGuard":"const isElementState = (s) =>\n  ['visible', 'hidden', 'stable', 'enabled', 'editable'].includes(s);","tryCatchPattern":"try {\n  el.waitForElementState(state, { timeout: '30s' });\n} catch (e) {\n  if (String(e).includes('timed out')) {\n    // app never reached the state: fail with context, not a retry loop\n    throw new Error(`element never became ${state}: ${e}`);\n  }\n  throw e;\n}","preventionTips":["Validate the state string against the supported set before calling","Size timeouts to the app's real transition duration","Do not use waitForSelector-only states (attached/detached) here"],"tags":["browser","wait","actionability","timeout","element-handle"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}