A flaky test passes and fails on the same code without any change, and it's an architecture problem, not a test problem. The fixes that work: track cumulative unique flaky tests (not per-run rate), treat quarantine as a coverage debt with owners and deadlines, debug failure clusters instead of individual tests, build isolation into the framework (condition-based waits, data factories, cached auth), and make ownership automatic. Retries are not a fix, they're a $100K/year way of hiding the problem.
A flaky test is a test that produces different results; pass or fail on the same code, with no changes in between. Run it ten times, get eight greens and two reds, change nothing. That's flake.
The danger isn't the failed runs. It's what flaky tests do to your team: once developers learn that red might mean nothing, they stop trusting red. Reruns become reflex. The CI gate still exists, but it stops gating anything.
Almost every flaky test traces back to one of eight causes:
Notice what's not on the list: "the testing framework." Playwright, Cypress, and Selenium get blamed constantly, but the framework is almost never the root cause. The architecture around it is.
If you're firefighting today, do these four things in order, the strategy can wait 48 hours:
grep -r "waitForTimeout" tests/ | wc -l (or sleep/cy.wait with fixed values). Every one is a deferred flake. This number is the fastest health check we run on any suite we inherit.Then come back and do the five fixes properly.
Three Questions to Find Out If You Actually Have a Problem
Before any solution, you need an honest read on your current exposure. Most teams are watching the wrong metric and drawing the wrong conclusion from it.
Answer these three questions using your actual CI data from the last 60 days.
You’ll See Results Like These
| Signal | Healthy | Warning | Critical |
| Unique flaky tests in 60 days | < 2% of the suite | 2–5% of the suite | > 5% of the suite |
| Quarantined tests with the named owner | All of them | Some of them | None or few |
| Failure timestamp correlation done | Yes, regularly | Once or never | Never attempted |
| Per-execution flaky rate | < 1% | 1–3% | > 3% |
| Team reaction when CI fails | Investigates root cause | Re-runs and moves on | Doesn't notice anymore |
If you're in the right-hand column for two or more rows, the retry budget you're spending isn't buying stability. It's buying silence.
Read Also: Top QA mistakes to avoid
Most teams track per-execution flaky rate — flaky results divided by total runs. It looks small and stays small while the problem grows.
Here's why: John Micco's research at Google showed that a 1.5% per-execution flaky rate touches 16% of your total test inventory over time. The per-run number whispers while a sixth of your suite becomes untrustworthy.
What to do instead:
The metric you are watching tells you how many runs failed today. What you actually need to know is how much of your suite can no longer be trusted.

(For the full measurement stack: flake rate, retry rate, first-attempt pass rate, quarantine dwell time, see our Playwright testing KPIs guide.)
Open your quarantine folder right now. Find the oldest test in it. Check when it was quarantined, then check whether a single comment, commit, or ticket explains why it was moved there or when it is coming back.
For most teams, the honest answer is: it was flagged, it was moved, and that was the last anyone thought about it. The test is still counted in your inventory. The coverage it was supposed to provide is quietly gone.
Martin Fowler named this failure mode directly, quarantined tests stop helping with regression coverage, and without accountability, the quarantine folder becomes a one-way door. Atlassian built its Flakinator system precisely because it knew engineers would not follow up on quarantined tests voluntarily.
Their fix was automatic routing to a named owner, a ticket, and a deadline. The design assumption was explicit: good intentions are not enough.
Every test behind that door is a regression your suite will no longer catch. Your coverage percentage looks the same. Your actual coverage does not.
Note: If your quarantine list only grows, you're not managing flake. You're archiving it.
The single biggest waste in flaky-test work is debugging tests one at a time when they fail together.
Understand it with an example: an engineer spends three hours chasing a flaky timeout in the payment confirmation test and fixes a hardcoded wait. The next week, a different engineer spends two hours on a race condition in the checkout flow. Different tests, different people, different days, but both failures trace to the same shared resource: a test environment database that is not properly isolated between parallel runs.

Two engineering sessions. One root cause. Fourteen more tests in quarantine with the same underlying condition, still waiting.
A 2025 University of Sheffield / Carnegie Mellon study found that 75% of flaky tests fail in correlated clusters, with a mean cluster size of 13.5 tests. That's not thirteen problems. That's one problem with thirteen symptoms, a shared environment issue, a data collision window, a service dependency.
The cost asymmetry is brutal. Daimler Truck AG's analysis put manual investigation at $5.67 per flaky failure versus $0.02 for a retry, which is exactly why teams default to retries, and exactly how the root cause survives to flake another day.

The clustering workflow:
This is where flake actually gets fixed in the framework, not the test files. When we rebuilt Centerbase's suite, these changes cut flaky failures by 85% and execution time by 60%:

Replace hard waits with condition-based waits. The single highest-value change in most suites.// Flaky: guesses how long rendering takesawait page.waitForTimeout(5000);await page.click('#submit');
// Stable: waits for the actual conditionawait page.getByRole('button', { name: 'Submit' }).click();// Playwright auto-waits for visibility and actionability
Use data factories, not shared fixtures. Every test creates its own isolated data and cleans up after itself:// Flaky: every test fights over the same userconst user = SHARED_TEST_USER;
// Stable: each test gets its ownconst user = await createTestUser({ role: 'admin' });
storageState does this natively. At Centerbase this alone cut ~60% of execution time, and shorter runs mean fewer timing windows for flake to happen in.getByRole, getByLabel) survive redesigns; brittle CSS chains don't.
retries: 2 for detection (the JSON reporter marks recovered tests flaky), never as the fix.cy.wait(3000) with fixed times is the same hard-wait trap. Use route interception (cy.intercept) to wait on actual network events.WebDriverWait with expected conditions everywhere, and treat any Thread.sleep as a defect. Most "Selenium is flaky" complaints are missing-wait-discipline complaints.Spotify cut its flakiness from 6% to 4% in two months by making flaky tests visible to the people who owned them. Before a single test was repaired, the accountability structure changed, and the rate dropped.

Jason Palmer says that without confidence in your test suite, you are in no better position than a team with zero tests. What your team needs is not more intent around ownership; it is infrastructure that makes ownership unavoidable.
Naming someone in a comment and moving on does not work. Forcing functions do: automatic tickets, fix-by dates with pipeline consequences, and escalation when deadlines pass without action.
Note: Infrastructure beats intent because intent doesn't survive sprint pressure. Tickets, SLAs, and pipeline rules do.
For a 100-person engineering team, the annual math looks like this:
| Cost Category | Annual Impact (100-person team) |
| Developer time investigating failures | ~$165,000 |
| Developer time repairing flaky tests | ~$195,000 |
| Retry-only "resolution" (50 failures/day) | ~$100,000+ |
| Total direct productivity loss | ~$375,000 |
Assumes ~100 engineers at blended US rates, investigation/repair time consistent with Daimler Truck AG's published per-failure costs.
And the problem is growing: Bitrise's industry reporting shows the share of teams naming flakiness a top CI problem rose from 10% to 26% between 2022 and 2025. AI-accelerated development is pushing more code, and more tests through the same pipelines.
Everything above is what we do in flaky-suite engagements, in roughly this order: run the 60-day diagnostic, cluster the failures, fix the architecture (waits, data factories, cached auth, locators), and leave behind the ownership infrastructure so it doesn't regress. It's the exact playbook from the Centerbase engagement 85% fewer flaky failures, 60% faster execution, regression cycle halved.
When to bring in outside help: when your team has been "fixing flaky tests" for two quarters and the cumulative count hasn't moved, that's the signal the problem is architectural, and inside-the-sprint effort can't reach it.