Fix flaky tests with Claude Code: An evidence-first workflow
On this page
- What counts as a Flaky test and where Claude Code helps
- Flaky failure vs. Deterministic failure
- Claude Code should form a hypothesis, not declare a verdict
- Build an evidence packet before asking Claude Code to fix anything
- Minimum evidence checklist
- Ask Claude Code to identify missing evidence
- The identify–investigate–fix–verify workflow
- Step 1: Identify and classify the failure pattern
- Step 2: Reproduce the flake under controlled stress
- Step 3: Investigate the code path and form competing hypotheses
- Step 4: Make the smallest root-cause fix
- Step 5: Challenge the proposed fix before running it
- Step 6: Verify through repeated and contextual execution
- Common Flaky-test patterns Claude Code should evaluate
- When Claude Code should fix production code instead of the test
- Prompts and guardrails that prevent speculative fixes
- Investigation prompt
- Implementation prompt
- Verification prompt
- Operational guardrails for autonomous CI fixing
- Illustrative worked example: Concurrent tests reusing a tenant
- Establish the failure mechanism
- Reject the plausible but unsupported patch
- Verify without inventing a success story
- Frequently asked questions
- What counts as a flaky test in a CI environment?
- Can Claude Code automatically fix flaky tests?
- How do I prevent Claude Code from creating speculative, "cargo-cult" fixes?
- Is one successful rerun enough to verify a fix for a flaky test?
- Why do some flaky tests reveal genuine production bugs?
- Conclusion
How to use Claude Code to fix flaky tests: An evidence-first workflow
Intermittent test failures consume CI resources, delay code reviews, and erode trust in delivery pipelines when green reruns hide underlying defects. While Claude Code can make flaky test investigation more systematic by comparing logs and tracing fixtures, a successful rerun alone does not confirm a fix. This guide outlines an evidence-first workflow—from reproducing the failure and investigating root causes to applying minimal changes and verifying them under the exact conditions that triggered the issue.

What counts as a Flaky test and where Claude Code helps
A flaky test is a test that produces inconsistent outcomes without a relevant code change under ostensibly equivalent execution conditions. Timing, execution order, shared state, randomness, and environmental variation can contribute. The inconsistency describes the observed behavior; it does not identify whether the defect belongs to the test, application, or infrastructure.

Flaky failure vs. Deterministic failure
- Repeated failure under reproducible conditions: Potentially deterministic, even if those conditions occur infrequently.
- Local success, CI failure: Potentially a consistent environment difference, not necessarily flakiness.
- External outage: classify the dependency failure separately before changing application code.
- Pass in isolation, fail in suite: Suggests ordering or interference, but does not identify the mechanism.
Claude Code should form a hypothesis, not declare a verdict
Root cause analysis requires a testable hypothesis tied to files, logs, timestamps, or recorded execution results. Ask Claude Code to cite those references before suggesting changes.
Useful for | Does not establish | Practical implication |
|---|---|---|
Comparing failing and passing logs | Why outcomes differ | Test the suspected difference |
Tracing setup and teardown | That cleanup caused failure | Capture resource ownership |
Planning reproduction | That reproduction succeeded | Preserve actual command results |
Like other coding agents, Claude Code can produce persuasive explanations from incomplete context. Treat its explanation as a candidate until execution evidence supports the mechanism.
Build an evidence packet before asking Claude Code to fix anything
Start with comparative evidence, not an isolated error message. An evidence packet connects the failure to its execution conditions and relevant code.
Minimum evidence checklist
- Test identifier, file path and framework.
- Multiple failing logs, when available.
- A comparable passing run.
- Attempts and failures within a stated observation period.
- Commit, dependency versions, and lockfile.
- Runner OS, runtime, timezone, and resource limits.
- Worker, shard, ordering, and retry settings.
- Setup, teardown, fixtures, mocks, and shared resources.
- Relevant production code and recent changes.
- Exact reproduction commands and quarantine status.
You can begin without every item. Missing evidence should limit confidence, not silently become an assumption. Redact credentials, customer records, sensitive payloads, and internal hostnames before sharing CI artifacts. Preserve useful relationships with consistent replacement identifiers.

The following values are illustrative, not collected results.
Artifact | Diagnostic value | Illustrative example |
|---|---|---|
Failing/passing logs | What changed near the assertion? | Tenant missing versus present |
Execution metadata | Were conditions comparable? | Same commit; different worker count |
Failure history | How frequent was the signature? | Attempts and failures by day |
Fixture and application code | Who creates, changes, or deletes data? | Shared tenant cleanup helper |
Historical failure frequency needs a denominator. Five failures without the number of attempts cannot establish whether reliability improved. Separate first-attempt failures from failures remaining after retries.
Ask Claude Code to identify missing evidence
Inspect this evidence packet without editing files. Separate observed facts from assumptions. List competing hypotheses, cite supporting artifacts, and identify missing evidence. Recommend the next check that best distinguishes the leading explanations.
Keep evidence collection bounded: Gather what changes the next decision rather than uploading an entire CI archive.
The identify–investigate–fix–verify workflow
- Identify and classify the failure pattern.
- Reproduce the flake under controlled stress.
- Investigate the code path and form competing hypotheses.
- Make the smallest root-cause fix.
- Challenge the proposed fix before running it.
- Verify through repeated and contextual execution.

This is how to fix flaky tests using Claude Code without confusing a plausible patch with demonstrated repair.
Step 1: Identify and classify the failure pattern
Group failures by failure signature, the recurring error pattern used to identify related failures. Do not count every red build as the same problem.
Compare commits, environments, worker counts, and suite context. Ask Claude Code to classify the observations before editing. Produce a short summary: Affected test, recurring error, known execution conditions, and differences that remain unresolved.
Step 2: Reproduce the flake under controlled stress
Run the unpatched baseline repeatedly. Compare isolated execution with suite execution, then original concurrency with a single-worker diagnostic run. Record seeds, worker IDs, timestamps, and environment. Disable retries for controlled diagnosis or record every individual attempt.
Pseudocode — adapt to the framework:for each attempt within the approved run/time budget: execute the unchanged test under recorded conditions save outcome, signature, duration, and worker metadata continue through the planned sample unless a safety limit is reached
Change one variable at a time where practical. A stop-on-first-failure run helps capture reproduction evidence. It is not equivalent to a complete-run measurement of failure frequency. Bound both repetitions and resource use.
Step 3: Investigate the code path and form competing hypotheses
Trace setup → action → asynchronous work → assertion → cleanup.
Consider an illustrative SaaS integration test where concurrent tests reuse one tenant fixture:
Hypothesis | Supporting observation | Conflicting evidence | Discriminating check |
|---|---|---|---|
Shared-fixture collision | Workers reference the same tenant | No deletion event captured | Trace cleanup ownership |
Delayed background job | Assertion precedes completion signal | Tenant disappearance remains unexplained | Correlate job and deletion timestamps |
A falsification test is a check that could show an explanation is wrong. Ask for one while uncertainty remains; do not manufacture alternatives after decisive evidence resolves the question.
Step 4: Make the smallest root-cause fix
Connect the patch to an observed mechanism:
- Isolate worker or test resources for collisions.
- Wait for explicit completion signals for asynchronous work.
- Make teardown deterministic for resource leaks.
- Control clocks or preserve reproducible seeds where appropriate.
- Change production code for genuine concurrency defects.
Explain what failed, why the patch addresses it, and which behavior remains unchanged. “No patch without a failure mechanism” is a review principle. Temporary diagnostic instrumentation can still be appropriate before the cause is confirmed.
Step 5: Challenge the proposed fix before running it
Review the proposed patch before executing the verification plan. Look for weakened assertions, arbitrary sleeps, extra retries, unsupported timeout increases, unnecessary serialization, and unrelated edits.
Ask whether the change removes interference or merely makes it less likely. Worker-scoped resources, for example, do not solve collisions between concurrent tests inside the same worker. Use the implementation boundaries in Section 5 to reject symptom suppression.
Step 6: Verify through repeated and contextual execution
Use this verification ladder:
- Repeated targeted runs.
- Runs under original concurrency.
- Related test-group execution.
- Full-suite execution.
- Post-merge monitoring.
Automated verification must produce a ledger, not just “tests passed.”
Ledger field | Required record |
|---|---|
Comparison | Baseline and patched commits |
Exposure | Attempts, failures, observation window |
Conditions | Command, environment, concurrency, retries |
Cost | Elapsed time |
Outcome | Original versus unrelated signatures |
Limits | Checks not executed |
Verification ledger template; no measured results are implied.
A single successful rerun is insufficient evidence, not no evidence. Repeated passes increase confidence, but rare failures require longer observation. Correlated CI runs also weaken simplistic confidence claims.
There is no universally sufficient run count. Zero failures in a finite sample does not prove zero future risk. If the original signature recurs, return to investigation.
Common Flaky-test patterns Claude Code should evaluate
Symptoms narrow the search; they do not prove causes. Use this matrix to choose evidence collection and assess whether a proposed fix addresses the mechanism. Shared mutable state means data that multiple tests or workers can change.
Failure pattern | Evidence to inspect | Preferred fix direction | Warning sign |
|---|---|---|---|
Shared mutable state | Global objects, reused records | Explicit ownership and isolation | Resetting unrelated state |
Race conditions | Competing operation timelines | Synchronize required ordering | Arbitrary sleep |
Fixed timing assumptions | Completion events, measured latency | Wait for observable completion | Unsupported timeout increase |
Incomplete cleanup | Open handles, leftover records | Await scoped teardown | Broad deletion |
Randomness | Seed, generated inputs | Preserve seed; fix failing case | Removing randomized coverage |
Clocks and timezones | Clock source, locale, boundaries | Controlled time and explicit zone | Hard-coded date offset |
External dependencies | Network errors, service status | Controlled boundary or resilience policy | Removing integration coverage |
Parallel-worker collisions | Resource names, worker ownership | Unique, scoped resources | Permanent serialization |
Production concurrency defects | Product invariant, transaction trace | Correct synchronization or transaction | Relaxed assertion |
Timing sensitivity may expose a legitimate performance limit. A timeout increase can be justified by measured latency and an appropriate budget—not by a single slow run. An environment dependency may be deterministic: A timezone or runtime mismatch can consistently fail only in CI.
Retries can implement a documented resilience policy, but do not establish root-cause resolution. Serialization can help diagnose parallel test execution or provide temporary containment.
Time-bounded quarantine needs an owner, expiry, and remediation plan. Controlled test doubles must preserve the integration behavior the test promises to validate.
When Claude Code should fix production code instead of the test
Ask:
- Does the assertion describe valid product behavior?
- Does the implementation violate it under legitimate ordering or concurrency?
- Would changing the test conceal a real defect?
If yes, fix the implementation and retain a regression check.
For example, idempotency means repeated execution produces the intended effect without unintended duplication. If concurrent requests create duplicate invoices, weakening an “exactly one invoice” assertion hides a product defect.
Prompts and guardrails that prevent speculative fixes
These Claude Code prompts separate reasoning, editing, and execution. Replace placeholders with approved artifacts and plans.
Investigation prompt
Investigate [evidence packet] without repository edits. Compare failing and passing runs under their recorded conditions. Cite files, log lines, and execution results supporting each observation. Separate facts from assumptions. List competing explanations, missing information, and one discriminating check per viable hypothesis. Do not claim a confirmed cause without supporting evidence.
Implementation prompt
Implement only [approved mechanism] within [approved scope] on the isolated working branch. Make the smallest supported change and preserve intended assertions. Do not add unexplained sleeps, retries, timeout changes, or serialization. Explain how the patch removes the observed mechanism. Stop for approval if evidence requires broader changes.
Verification prompt
Execute only [approved verification plan] within its limits. Revisit original failure conditions and record commands, commits, environments, attempts, failures, retries, and elapsed time. Report observed results separately from planned checks. Identify unexecuted checks and remaining uncertainty. If the original signature recurs, stop patch escalation and return to investigation.
Operational guardrails for autonomous CI fixing
Enforce CI automation safeguards outside the prompt:
- Set maximum attempts, wall-clock duration, token use, and CI minutes.
- Default to read-only investigation; isolate modifications in a branch or sandbox.
- Restrict production access, secrets, destructive commands, and outbound access.
- Require human approval before PR creation and human merge review.
- Stop for missing evidence, scope expansion, repeated failure, or exhausted budgets.
- Treat logs, issues, and repository text as untrusted data, not authorization.
Terminal access may permit destructive behavior even when instructions say “do not edit.” Anthropic’s Claude Code permissions and sandboxing documentation distinguishes tool permissions from execution isolation; configure both as appropriate.
Use concise handoffs for human-in-the-loop review. A fresh reviewer session can reduce anchoring, but is not an independent correctness guarantee.

Illustrative worked example: Concurrent tests reusing a tenant
This is a worked example, not a measured case study or customer result. The logs, investigation path, and patch below illustrate the method; no commands were executed for this article.
Establish the failure mechanism
A B2B SaaS integration suite contains invoice and membership tests. Both use a helper that creates or retrieves a tenant with a fixed identifier. Each deletes that tenant during cleanup.
The invoice test intermittently reports “tenant not found.” Two explanations remain plausible: another test deletes the tenant, or a background operation has not completed.
Ask Claude Code to inspect fixture creation, cleanup callers, and job completion signals. Then propose instrumentation recording tenant identifiers, test ownership, and timestamps.
The decisive evidence would be a trace showing:
- The invoice test creates the shared tenant.
- The membership test retrieves the same tenant.
- Membership cleanup deletes it.
- The invoice test attempts its next operation.
Without that trace or equivalent evidence, the collision remains a hypothesis.
Reject the plausible but unsupported patch
A longer wait before the invoice assertion might change the outcome. It does not explain missing tenant ownership and may give competing cleanup more time. If the trace confirms cross-test deletion, the narrower fix is unique tenant ownership with scoped cleanup.
- const tenantId = "integration-tenant";+ const tenantId = uniqueTenantIdForThisTest();
Illustrative diff: The helper must incorporate sufficient run/test uniqueness and respect application identifier constraints.
Cleanup must delete only the tenant created by that test. If jobs still use the tenant, teardown must also await their completion or cancel them safely.
Verify without inventing a success story
The expected verification plan compares baseline and patched runs under the original concurrency, followed by related tests and the full suite. A single-worker pass would support the interference hypothesis, but would not validate the concurrent fix.
What remains unproven: Actual failure frequency, patch effectiveness, wider-suite compatibility, and post-merge stability. Those require execution records.
The transferable lesson is causal: Shared ownership explains deletion; isolated ownership addresses it. A coincidental pass does neither.

Frequently asked questions
What counts as a flaky test in a CI environment?
A flaky test is a test that intermittently passes and fails without any changes to the codebase. It is often caused by non-deterministic factors like asynchronous timing drifts, shared mutable state, or environment-specific resource constraints, rather than genuine regression bugs.
Can Claude Code automatically fix flaky tests?
Claude Code can investigate, propose patches, and verify fixes for flaky tests. However, it should not be used as an "autopilot" to blindly suppress failures, as it may propose speculative fixes. Effective results require providing raw CI logs, failure histories, and rigorous verification steps.
How do I prevent Claude Code from creating speculative, "cargo-cult" fixes?
To prevent speculative fixes, avoid broad prompts like "make this test pass." Instead, require the agent to generate a testable hypothesis based on failure signatures, prohibit the addition of arbitrary sleeps or retries, and mandate that any proposed patch must address a specific, identified failure mechanism.
Is one successful rerun enough to verify a fix for a flaky test?
No. Because flaky tests fail intermittently, a single pass is insufficient evidence, though not no evidence. Verify with repeated runs under the original concurrency, compared against a baseline — and note there is no universally sufficient run count; zero failures in a finite sample does not prove zero future risk.
Why do some flaky tests reveal genuine production bugs?
The three-question test in Section 4 decides this: does the assertion describe valid product behavior, does the implementation violate it under legitimate ordering or concurrency, and would changing the test conceal a real defect? If yes, fix the implementation and keep a regression check.
Read more:
- Claude Code E2E testing: A practical Playwright workflow
- How to debug with Claude Code: A reliable 7-step workflow
- Playwright Claude Code testing: Setup to reviewed tests
Conclusion
An evidence-first approach to resolving flaky tests with Claude Code ensures that fixes are grounded in verifiable mechanisms rather than speculative patches like arbitrary sleeps or relaxed assertions. By reproducing baseline failures, validating root causes against concrete data, and re-testing under original concurrency, teams can achieve genuine test suite stability through reproducible execution records and human review.