Skip to content
Latchkey

Playwright "strict mode violation" - Locator Resolved to Multiple

Playwright runs locators in strict mode: an action or assertion targeting a locator that matches more than one element is an error, not a "pick the first." The selector is too broad for the page.

What this error means

A click/fill/expect fails with "strict mode violation: locator resolved to 2 elements." The page legitimately has several matching nodes, and Playwright refuses to guess which one you meant.

Playwright output
Error: strict mode violation: getByRole('link', { name: 'Edit' })
resolved to 3 elements:
  1) <a href="/items/1">Edit</a>
  2) <a href="/items/2">Edit</a>
  3) <a href="/items/3">Edit</a>

Common causes

Locator matches repeated UI

A list or table renders the same label/role many times. A locator like getByText('Edit') matches every row, violating strict mode.

Name match is too loose

A substring name match (getByRole('button', { name: 'Save' })) also matches "Save and close," so more than one element qualifies.

How to fix it

Scope the locator to a unique ancestor

Chain from a row/region so the match is unique, or use an exact name.

spec.ts
// scope to the right row
await page.getByRole('row', { name: 'Invoice 42' })
          .getByRole('link', { name: 'Edit' }).click();
// or require an exact name
await page.getByRole('button', { name: 'Save', exact: true }).click();

Select a specific match when duplicates are expected

  1. Use .first(), .last(), or .nth(i) only when you truly want a positional element.
  2. Prefer a stable getByTestId per item over positional indexing.
  3. Add a unique accessible name or test id to the target in the app.

How to prevent it

  • Give actionable elements unique accessible names or test ids.
  • Scope locators to a row/region instead of the whole page.
  • Use exact: true when a name is a prefix of another.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →