## TL;DR

`cy.get()` times out when the selector never matches within the default timeout. First check the selector actually exists in the DOM at that moment, then decide whether the fix is a better selector, a longer timeout, or waiting on the right condition (network idle, element actionable) instead of a fixed wait.

## Error

```text
CypressError: Timed out retrying after 4000ms: Expected to find element: `[data-cy=submit]`, but never found it.
```

## Steps

1. Open the Cypress runner and click the failed `cy.get()` command to see the DOM snapshot at failure time. Expected: you see the page state when the assertion ran.
2. In the browser console of the snapshot, run `document.querySelector('[data-cy=submit]')`. Expected: null means the selector is wrong or the element renders later; an element means a timing issue.
3. If the selector is wrong, switch to a stable attribute (`data-testid`, `data-cy`) instead of classes or structure. Expected: the query returns exactly one element.
4. If the element renders late (after an API call), replace the get with an intercept wait: `cy.intercept('GET', '/api/items').as('items'); cy.wait('@items')` before the get. Expected: test waits for data, not a fixed time.
5. If the element is genuinely slow, raise the timeout on that command only: `cy.get('[data-cy=submit]', { timeout: 10000 })`. Expected: command retries up to 10s instead of 4s.

## When to use

- The failure message is `Timed out retrying` on `cy.get()`, `cy.contains()`, or `cy.find()`.
- The test passes sometimes and fails others (timing), or fails consistently (selector).
- You can reproduce locally in the Cypress interactive runner.

## When not to use

- The timeout is on `cy.visit()` (server never responded; different cause).
- The error is `element is detached from the DOM` (re-render race; see that skill).
- You are using Playwright or Selenium (different retry model).

## Tool compatibility

- Cypress 10 through 14, any browser Cypress supports.
- Applies to `cy.get`, `cy.contains`, `cy.find`, `cy.get().should()` chains.

## Variant phrasings

### Timed out retrying after 4000ms

The default timeout is 4000ms, configurable per command or globally via `defaultCommandTimeout`.

### Expected to find element but never found it

Same root pattern: selector evaluated repeatedly against a DOM that never contained a match.

## Why it happens

Cypress retries the query until the timeout, then fails. The usual causes are a selector that does not match anything (typo, dynamic class, wrong attribute), an element that appears only after async work the test did not wait for, or a page that navigated away before the query resolved.

## Edge cases

- `cy.get()` inside a `.then()` callback does not retry the way top-level commands do; restructure to keep queries at the top level.
- Increasing the global timeout masks slow pages; prefer targeted `{ timeout }` on the slow command.
- Elements inside iframes are invisible to `cy.get()` without the iframe plugin; a timeout there means a scoping problem, not a missing element.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_VlT0XtnxAKr20gw_Z1y7vw
