Cypress "Timed out retrying after 4000ms" - Fix Flaky Assertions
By Daniel Zoghalchali·Latchkey
Cypress retried a command/assertion for its timeout window (4000 ms by default) and the condition never became true. Usually the element renders slower than the timeout in CI, or the selector no longer matches.
What this error means
A command fails with "Timed out retrying after 4000ms: Expected to find element: 'X', but never found it." It often passes locally and on the headed app but flakes on a slower CI runner.
Cypress output
Timed out retrying after 4000ms: Expected to find element:
`[data-testid="submit"]`, but never found it.
Common causes
Element renders slower than the timeout in CI
On a loaded runner the app paints later than locally. The default 4s retry window expires before the element appears - a timing-only flake.
Selector no longer matches
A markup or data-testid change means the selector matches nothing. This is deterministic, not flaky, and a longer timeout will not help.
Asserting before the app settles
Asserting immediately after an action that triggers async work (XHR, animation) races the UI; without retry-able assertions it can miss the final state.
How to fix it
Assert on the actual readiness signal
Wait on the network or a visible state change rather than a fixed sleep, so the test is fast when possible and patient when needed.
cy.get('[data-testid="submit"]', { timeout: 15000 }).should('exist');
// or globally in cypress.config.js: defaultCommandTimeout
How to prevent it
Wait on intercepted requests, never cy.wait(<ms>).
Use stable data-testid selectors decoupled from styling.
Tune defaultCommandTimeout for the slowest CI tier.
Frequently asked questions
What causes ""Timed out retrying""?
On a loaded runner the app paints later than locally. The default 4s retry window expires before the element appears - a timing-only flake.
How do I fix "Timed out retrying"?
Wait on the network or a visible state change rather than a fixed sleep, so the test is fast when possible and patient when needed.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.