microsoft/playwright · error · NonRecoverableDOMError
Element is not ${result.missingState}
Error message
Element is not ${result.missingState} What it means
The action returned an object with `missingState`, a state precondition that did not hold (e.g. the element should be enabled/stable/editable but was not). With force:true or noAutoWaiting the loop cannot wait for the state, so it throws NonRecoverableDOMError(`Element is not <missingState>`).
Source
Thrown at packages/playwright-core/src/server/dom.ts:372
throw new NonRecoverableDOMError('Did not find some options');
progress.log(' did not find some options');
continue;
}
if (result === 'error:optionnotenabled') {
if (noAutoWaiting)
throw new NonRecoverableDOMError('Option being selected is not enabled');
progress.log(' option being selected is not enabled');
continue;
}
if (typeof result === 'object' && 'hitTargetDescription' in result) {
if (noAutoWaiting)
throw new NonRecoverableDOMError(`${result.hitTargetDescription} intercepts pointer events`);
progress.log(` ${result.hitTargetDescription} intercepts pointer events`);
continue;
}
if (typeof result === 'object' && 'missingState' in result) {
if (noAutoWaiting)
throw new NonRecoverableDOMError(`Element is not ${result.missingState}`);
progress.log(` element is not ${result.missingState}`);
continue;
}
return result;
}
}
async _retryPointerAction(progress: Progress, actionName: ActionName, waitForEnabled: boolean, action: (progress: Progress, point: types.Point) => Promise<void>,
options: { waitAfter: boolean | 'disabled' } & types.PointerActionOptions & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
// Note: do not perform locator handlers checkpoint to avoid moving the mouse in the middle of a drag operation.
const skipActionPreChecks = actionName === 'move and up';
return await this._retryAction(progress, actionName, async (progress, retry) => {
// By default, we scroll with protocol method to reveal the action point.
// However, that might not work to scroll from under position:sticky elements
// that overlay the target element. To fight this, we cycle through different
// scroll alignments. This works in most scenarios.
const scrollOptions: (ScrollIntoViewOptions | undefined)[] = [
undefined,View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Remove force:true so Playwright waits for the required state.
- Satisfy the precondition that brings the element into the needed state (fill required fields to enable the button).
- Inspect the missingState value in the message to know which state failed and address it.
Example fix
// before
await page.locator('#submit').click({ force: true }); // disabled → throws 'not enabled'
// after
await page.locator('#email').fill('a@b.com'); // enables submit
await page.locator('#submit').click(); Defensive patterns
Strategy: retry
Validate before calling
// Meet the missing state, then act without force.
await page.locator('#email').fill('a@b.com'); // enables the button
await page.locator('#submit').click(); Prevention
- Do not force actions that need a state precondition; let auto-wait handle it.
- Inspect the missingState token in the message to know which state failed.
- Satisfy preconditions (fill fields, wait for editable/enabled) first.
When it happens
Trigger: Performing a forced action when a state precondition — enabled, editable, stable — is false; e.g. clicking a button that is disabled with force:true, or typing into a readonly input with force.
Common situations: Disabled submit buttons tested with force before validation enables them; readonly fields; elements still animating (unstable) when force was used.
Related errors
- Element is not visible
- Element is outside of the viewport
- Did not find some options
- ${result.hitTargetDescription} intercepts pointer events
- Option being selected is not enabled
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/8f7b7e40c67e7c53.
Report an issue: GitHub.