How do I stop an AI coding agent getting stuck in a fix-break-fix loop?

Ivo, laptop under his arm, comes round again in an office revolving door, eyes rolled up in comic exasperation.

TL;DR

When a coding agent fixes one failure and brings back another, each patch usually satisfies one check while something it cannot see pulls the other way: a second defect, or two requirements that disagree. Stop patching the second time an earlier failure returns. Keep a written record of every attempt, run all the affected checks together, investigate one bounded hypothesis without editing, then leave a regression test and a short note for the next session. That cannot guarantee the right diagnosis, but it shows where the loop comes from.

What a loop detector counts as progress

Gemini CLI has a built-in loop check. Part of it periodically asks a second model whether the session is stuck, and that model's instructions draw a careful line. An agent that applies the same edit and hits the same error each cycle is looping, but "If the assistant is modifying different code or getting different errors, that is debugging progress, not a loop" (Gemini CLI loop detection source). Its other checks catch the same tool call with the same arguments five times running.

By that definition a fix-break-fix loop counts as progress: every attempt changes different code and produces a different failure. It is debugging that keeps returning to where it started.

A Cursor user described this on the Cursor forum in April 2025: the agent fixed a bug, the fix introduced a new error, and fixing that brought the original bug back, over and over. They asked how to prevent it and how to stop the agent forgetting earlier fixes. In July 2025 someone asked on Hacker News whether others saw the same with paid chat assistants on simple bash scripts: they went round in circles, finding a fix and then losing it in later changes.

Two defects that take turns failing

A small example, written for this article, shows one structure that produces the loop. A pagination helper should turn page 1 into offset 0, but it multiplies the page number by the page size. The API handler that calls it subtracts one from the page first, which hides the mistake. A unit test covers the helper and an API test covers the handler. Running all four combinations gives this:

Comparison

State of the codeHelper unit testAPI test
Both defects present (the starting point)failspasses
Helper fixed, handler unchangedpassesfails: page 1 asks for offset -10
Handler fixed, helper unchangedfailsfails
Both fixed in one changepassespasses

Asked to make the unit test pass, an agent fixes the helper, and the API test breaks. Asked to fix the API test, the quickest change that turns it green restores the old helper, and the unit test fails again. No single fix can end the loop: the passing state needs both edits in one change, and the agent is looking at whichever test failed last.

The same shape appears when two requirements disagree: one test expects the old behaviour, another expects the new, and only a person can say which is right. Or the fix is checked against a reproduction that never exercises the failing path. In each case another patch cannot help: what is missing is information, not effort.

Keep a record of every attempt

The loop survives because nothing remembers it: once the context is compacted or cleared, the earlier attempts are gone. Claude Code's best-practice guide recommends clearing it: if you have corrected Claude more than twice on the same issue, the context is "cluttered with failed approaches", so run /clear and start again with a more specific prompt that incorporates what you learned (Claude Code best practices). A study of 18 models on HumanEval problems found that debugging effectiveness decayed quickly over successive attempts, with most models losing 60 to 80% of it within two or three, and that restarting from the original problem at the right moment recovered some of it (Adnan and Kuhn, the Debugging Decay Index, published in Scientific Reports). The problems were small, so read the numbers as a direction only.

A fresh session only helps if what you learned survives the reset. Keep it outside the chat, in a short file the next attempt starts from:

  • What changed. One line per attempt: the files, the hypothesis behind the change, and the commit or checkpoint to return to.
  • What it fixed and what it broke. The failing checks before and after, by name.
  • Which earlier failure returned. When an attempt brings back a failure seen before, note the attempt that first fixed it. The second such note is the signal to stop.
  • What was ruled out. Hypotheses the evidence contradicted, so nobody tries them again.

Commit or checkpoint before each attempt. Claude Code's rewind does not capture changes made through shell commands, and the same guide says it is no replacement for git. With one commit per attempt, a diff shows what each attempt actually changed, which is not always what the agent said.

Stop editing the second time a failure comes back

When to stop patching

  • If an earlier failure returns for the second time, stop and investigate.
  • If two attempts in a row taught you nothing new, do the same.
  • If two tests disagree about the expected behaviour, a person decides which is right.
  • If nobody can reproduce the failure on demand, build the reproduction first.

An investigation is a different kind of session, not a longer one, with one bounded hypothesis and no edits to production code until it is confirmed or rejected:

  1. Write the reproduction first. One command that runs every check involved in the loop together, from a clean state, so no fix can pass one check while quietly failing another. In the example, both tests in one run.
  2. State one hypothesis and what would disprove it. "The handler compensates for the helper" predicts that removing the compensation alone breaks the API test for page 1. If it does not, the hypothesis is wrong.
  3. Investigate without editing. In plan mode or a read-only session, ask the agent to trace the path and cite files and lines. Set a time or turn limit.
  4. Decide what is right before deciding how to fix it. If two tests or requirements disagree, a person chooses which one stands and records why; the article on stopping an agent weakening tests just to make them pass covers that judgement.
  5. Make one change that passes the whole reproduction, then run the full suite.

Research supports bringing in more than the agent's own view of its code. A study of models repairing their own programs found the gains were limited by the quality of their self-feedback; better feedback, including from people, helped more (Olausson et al., ICLR 2024). A study of four coding agents on 404 multi-hunk bugs, defects that need coordinated edits in several places, found that repair accuracy fell as the edits were more spread out, and that failed repairs did not fail fast: they used 33% to 440% more input tokens than successful ones (Nashid et al., accepted in ACM TOSEM).

Illustration of Noor seated beside Ivo on a flight of concrete steps by a metal handrail, her hand on his shoulder, as he talks with one hand raised and his closed laptop resting on his knees.
The second time an old failure comes back, stop patching and start investigating.

Leave a test and a note for the next session

Once the loop is broken, two things keep it from coming back. The first is a pair of tests kept together: the helper's own contract, and the interaction, page 1 requested through the handler reaching offset 0. The interaction test also passes at the starting point, because the two defects cancel out, so reverting the whole fix leaves it green and only the helper test catches it. Check all four states from the table: the combined suite should pass only when both are fixed. The second is a short investigation record committed next to the code: the symptom, each attempt and what it broke, the hypothesis that held, the evidence for it and anything still unexplained. What else belongs in a hand-over is covered in the article on what to save for a new AI coding session.

Paqad's root cause analysis workflow writes that kind of record in a fixed form: one document under docs/rca/ with the same sections in the same order, from problem statement and evidence to root cause and verification. A lint script rejects output that departs from that order. The skill is told to capture evidence before concluding, to ask when the evidence cannot separate a root cause from speculation, and never to present a guess as confirmed. During feature development, which proof method validates a fix is a decision for a person: when the agent raises it on a host with Paqad's hooks, edits stay blocked until you answer.

The limits matter. The workflow is designed for incidents after the fact, so using it on a stuck session is your call, and the lint checks structure, not whether the diagnosis is right. Nothing in Paqad watches a session and stops it for looping. Its workflow file accepts a cap on build, check and fix rounds, but in 1.91.1 no Paqad command runs that loop, so the cap is not mechanically enforced in an ordinary session; a stopping rule in your prompt is an instruction the agent can still miss. Flaky-test ownership and incident policy stay with your team. Paqad's classification page lists the phrase table that sends a root cause analysis request to that workflow ahead of an ordinary bug fix.

Illustration of Ivo standing at a wooden desk under a lit orange lamp, writing in a spiral notepad beside his open laptop, calm and faintly smiling.
A written record of what each attempt broke lets the next session start from the evidence, not the loop.

Frequently Asked Questions

Put the stopping rule in the prompt before the loop starts. Give the agent the single command that runs all the affected checks, say that an attempt only counts if all of them pass together, and tell it to stop and report, rather than try another variation, when a failure it already fixed comes back.

Reconstruct it from the code, not from the agent's summary. Diff consecutive commits or checkpoints, and list the failing checks after each run. A failure that disappears and later reappears is the loop's fingerprint, and the attempt that first fixed it usually touches the code the two defects share.

First check whether every attempt was verified against the same command. If the agent ran only the test that failed last, the loop lives in the verification. Then look for two assertions or requirements that expect different results from the same input, and use the version history to find when and why each was added.

Agree the limit before you start, as a number of attempts or a length of time, so the decision is not made while hoping the next patch works. If the investigation rejects its hypothesis, write a new one rather than return to patching, and after two rejected hypotheses bring in the person who knows that part of the code.

Name the test after the interaction it guards, so a later reader does not delete it as redundant. Keep the record where the next session will read it, beside the module or in its documentation. Add a line to the agent's instruction file only if the same trap is likely to recur there.