{"record":{"id":"9f055240ebb77001","repo":"microsoft/playwright","slug":"state-expected-one-of-attached-detached-visible","errorCode":null,"errorMessage":"state: expected one of (attached|detached|visible|hidden)","messagePattern":"state: expected one of \\(attached\\|detached\\|visible\\|hidden\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/frames.ts","lineNumber":845,"sourceCode":"  private async _evaluateExpressionHandle(expression: string, options: { isFunction?: boolean, world?: types.World } = {}, arg?: any): Promise<js.JSHandle<any>> {\n    const context = await this.context(options.world ?? 'main');\n    const value = await context.evaluateExpressionHandle(expression, options, arg);\n    return value;\n  }\n\n  async querySelector(progress: Progress, selector: string, options: types.StrictOptions): Promise<dom.ElementHandle<Element> | null> {\n    this.apiLog(`    finding element using the selector \"${selector}\"`);\n    return progress.race(this.selectors.query(selector, options));\n  }\n\n  async waitForSelector(progress: Progress, selector: string, performActionPreChecksAndLog: boolean, options: types.WaitForElementOptions, scope?: dom.ElementHandle): Promise<dom.ElementHandle<Element> | null> {\n    if ((options as any).visibility)\n      throw new Error('options.visibility is not supported, did you mean options.state?');\n    if ((options as any).waitFor && (options as any).waitFor !== 'visible')\n      throw new Error('options.waitFor is not supported, did you mean options.state?');\n    const { state = 'visible' } = options;\n    if (!['attached', 'detached', 'visible', 'hidden'].includes(state))\n      throw new Error(`state: expected one of (attached|detached|visible|hidden)`);\n    if (performActionPreChecksAndLog)\n      progress.log(`waiting for ${this._asLocator(selector)}${state === 'attached' ? '' : ' to be ' + state}`);\n    const promise = this.retryWithProgressAndBackoff(progress, async (progress, continuePolling) => {\n      if (performActionPreChecksAndLog)\n        await this._page.performActionPreChecks(progress);\n\n      if (scope && await progress.race(scope.evaluateInUtility(([injected, node]) => node.isConnected, {})) !== true)\n        throw new dom.NonRecoverableDOMError('Element is not attached to the DOM');\n\n      const resolved = await progress.race(this.selectors.callOnSelectorHandle(selector, { ...options, scope }, ({ injected, elements }) => {\n        const element: Element | undefined  = elements[0];\n        const visible = element ? injected.utils.isElementVisible(element) : false;\n        let log = '';\n        if (elements.length > 1)\n          log = `  locator resolved to ${elements.length} elements. Proceeding with the first one: ${injected.previewNode(elements[0])}`;\n        else if (element)\n          log = `  locator resolved to ${visible ? 'visible' : 'hidden'} ${injected.previewNode(element)}`;\n        return { log, element, visible, attached: !!element };","sourceCodeStart":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/frames.ts#L827-L863","documentation":"waitForSelector validates that options.state is one of 'attached', 'detached', 'visible', 'hidden'. Any other value throws 'state: expected one of (attached|detached|visible|hidden)'.","triggerScenarios":"Passing an invalid state such as 'load', 'networkidle', 'stable', undefined-as-string, or a typo like 'visble'. Most commonly confusing waitForSelector's state with waitForLoadState's lifecycle values.","commonSituations":"Migrating between the two wait APIs; auto-generated code passing the wrong enum; typos; passing 'load'/'networkidle' from a shared config object.","solutions":["Use one of: attached|detached|visible|hidden.","Move lifecycle waits (load/domcontentloaded/networkidle) to page.waitForLoadState.","Type the option narrowly (e.g. a string-literal union) to catch typos at compile time."],"exampleFix":"// before\nawait page.waitForSelector('#x', { state: 'load' }); // throws\n// after\nawait page.waitForSelector('#x', { state: 'visible' });\nawait page.waitForLoadState('load');","handlingStrategy":"validation","validationCode":"const VALID = ['attached','detached','visible','hidden'] as const;\nif (!VALID.includes(opts.state)) throw new Error(`state must be one of ${VALID.join('|')}`);","typeGuard":"type State = 'attached'|'detached'|'visible'|'hidden';\nfunction isValidState(s: string): s is State {\n  return ['attached','detached','visible','hidden'].includes(s);\n}","tryCatchPattern":"null","preventionTips":["Type the option as a string-literal union so the compiler rejects bad values.","Keep element-state and lifecycle-state options in distinct, typed objects."],"tags":["selector","validation","state"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}