microsoft/playwright · error · NonRecoverableDOMError
Element is not visible
Error message
Element is not visible
What it means
During the action retry loop (_retryAction), when an action returns 'error:notvisible' the normal behavior is to log and keep auto-waiting. But if force:true or noAutoWaiting is set, Playwright cannot retry, so it throws a NonRecoverableDOMError('Element is not visible') immediately. The element exists but has zero visible bounding box (display:none, visibility:hidden, opacity:0, or off-flow).
Source
Thrown at packages/playwright-core/src/server/dom.ts:342
if (retry) {
progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}`);
const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)];
if (timeout) {
progress.log(` waiting ${timeout}ms`);
const result = await progress.race(this.evaluateInUtility(([injected, node, timeout]) => new Promise<void>(f => setTimeout(f, timeout)), timeout));
if (result === 'error:notconnected')
return result;
}
} else {
progress.log(`attempting ${actionName} action${options.trial ? ' (trial run)' : ''}`);
}
if (!options.skipActionPreChecks && !options.force && !noAutoWaiting)
await this._frame._page.performActionPreChecks(progress);
const result = await action(progress, retry);
++retry;
if (result === 'error:notvisible') {
if (options.force || noAutoWaiting)
throw new NonRecoverableDOMError('Element is not visible');
progress.log(' element is not visible');
continue;
}
if (result === 'error:notinviewport') {
if (options.force || noAutoWaiting)
throw new NonRecoverableDOMError('Element is outside of the viewport');
progress.log(' element is outside of the viewport');
continue;
}
if (result === 'error:optionsnotfound') {
if (noAutoWaiting)
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');View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Remove force:true so Playwright's auto-wait retries until the element becomes visible.
- Ensure the element is visible before the forced action: await locator.waitFor({ state: 'visible' }).
- Fix the page flow so the element is visible when acted upon (open the tab/accordion first).
- If the element is intentionally hidden and you must interact, scroll/expand it via the UI first.
Example fix
// before
await page.locator('#hidden-btn').click({ force: true }); // throws
// after
await page.locator('#open-panel').click(); // make it visible
await page.locator('#hidden-btn').click(); // auto-wait handles it Defensive patterns
Strategy: retry
Validate before calling
// Let Playwright auto-wait by not forcing; or pre-check visibility.
await locator.waitFor({ state: 'visible' });
await locator.click(); // no force — retries until visible Prevention
- Avoid force:true for elements that may be hidden; rely on auto-wait.
- Open/expand the containing UI so the element is visible before acting.
- Pre-check with locator.isVisible() or waitFor({ state: 'visible' }).
When it happens
Trigger: Calling click()/fill()/press() etc. with { force: true } on an element that is present in the DOM but not rendered visible; acting with force on an element inside a hidden tab/accordion; element whose CSS makes it non-visible at action time.
Common situations: Using force:true to bypass actionability checks when the element is genuinely hidden; toggling UI state that hasn't completed its animation; clicking inside a container that is display:none until a parent action runs.
Related errors
- Element is outside of the viewport
- Did not find some options
- ${result.hitTargetDescription} intercepts pointer events
- Element is not ${result.missingState}
- Option being selected is not enabled
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/06312bfd9088af84.
Report an issue: GitHub.