Blog

Fix flaky tests with Claude Code: An evidence-first workflow

Goon Nguyen•Claude Code Guides••13 min read

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.

Fix flaky tests with Claude Code: An evidence-first workflow

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.

Fix flaky tests with Claude Code: An evidence-first workflow

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.

Fix flaky tests with Claude Code: An evidence-first workflow

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

  1. Identify and classify the failure pattern.
  2. Reproduce the flake under controlled stress.
  3. Investigate the code path and form competing hypotheses.
  4. Make the smallest root-cause fix.
  5. Challenge the proposed fix before running it.
  6. Verify through repeated and contextual execution.
Fix flaky tests with Claude Code: An evidence-first workflow

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:

  1. Repeated targeted runs.
  2. Runs under original concurrency.
  3. Related test-group execution.
  4. Full-suite execution.
  5. 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:

  1. Does the assertion describe valid product behavior?
  2. Does the implementation violate it under legitimate ordering or concurrency?
  3. 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.

Fix flaky tests with Claude Code: An evidence-first workflow

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:

  1. The invoice test creates the shared tenant.
  2. The membership test retrieves the same tenant.
  3. Membership cleanup deletes it.
  4. 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.

Fix flaky tests with Claude Code: An evidence-first workflow

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:

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.

Share this article