Claude Code Stuck in a Loop — How to Break Out

Agent repeats the same edit, oscillates between two states, or chases a flaky test forever. Six loop signatures and the one-prompt fix for each.

Claude Code is running pnpm test for the eighth time. Each iteration: edit the same expect(...).toBe(...) line, run again, fail again, revert. Or it’s ping-ponging between two interpretations of “fix the auth bug” — fixing OAuth, breaking magic-link, fixing magic-link, breaking OAuth. Tokens burn, progress bar doesn’t move. The agent is in a loop.

95% of loops aren’t “the model can’t fix this” — they’re a broken feedback loop: flaky test, under-constrained prompt, polluted context, or unflagged tool failure. The fix isn’t a smarter model; it’s identifying the loop signature in 30 seconds and breaking it with one targeted prompt. Below: the six loop shapes and the one-sentence constraint that breaks each.

Common causes

Ordered by hit rate, highest first.

1. Flaky test — pass / fail / pass / fail

The single most common trigger. A test uses Date.now(), network calls, randomness, or snapshot timestamps. Same code passes one run, fails the next. Agent sees red → edits → green → next run red → reverts → green → edits → red. Forever.

How to spot it: Stop the agent. Run the same command 3 times yourself without touching code. If you can reproduce green/red/green, the test is the problem.

2. Ambiguous prompt — agent oscillates between interpretations

“Fix the login bug” — but you have OAuth and magic-link. Agent fixes OAuth, magic-link test fails. Switches to magic-link, OAuth test fails. Bounces between mutually exclusive interpretations.

How to spot it: Look at the last 5 diffs. If they touch two different files in different features, each reverting the previous, the prompt is under-constrained.

3. Plan is wrong but agent refuses to replan

Agent committed to “change schema → change API → change UI.” Step 1 is impossible (table has data, can’t drop column). Agent stays on step 1 rewriting migrations forever instead of replanning.

How to spot it: Ask the agent “what’s your current plan + which step are you on?” If it says “still on step 1” for 5+ iterations, force a replan.

4. Context saturated with old errors

Long session, 80% of context is stale “previous failure” logs. Agent fits to old errors that no longer reflect current code state.

How to spot it: Open fresh session, paste current code, restate goal. If it succeeds first try, context pollution was the cause.

5. Agent ping-pongs between mock and real

Writes a mock to make test pass, next iteration decides mock is unrealistic, edits real implementation, original test breaks, goes back to mock. Loop.

How to spot it: Search the diff trail for jest.mock / vi.mock / MagicMock being added and removed across runs.

6. Tool call failed but agent didn’t notice

Bash returned a non-zero exit code. Agent parsed stdout as success and ran the same command again. Loop because the “failure signal” was invisible.

How to spot it: Check exit codes of last 3 tool calls. Non-zero but Claude didn’t say “command failed” = it missed the failure.

Shortest path to fix

Ordered by ROI. Step 1 + 2 break most loops in under a minute.

Step 1: Stop the agent, read the last 10 actions

Hit Esc / Stop. Then ask:

List the last 10 actions (file path + edit summary + command + exit code).
No commentary. Just a table.

90% of the time you’ll see two files alternating, the same line edited repeatedly, or repeated test runs without code progress. The pattern reveals the loop signature.

Step 2: Break with a one-sentence constraint

Match the loop signature to its constraint:

Loop typeConstraint prompt
Edits same test expectation”Don’t touch the test. The test is right — change the implementation to match.”
Adds/removes mocks”Keep the real implementation. Delete all mocks and run the integration test.”
Rewrites migrations”Schema is frozen. Restart the plan but only touch the UI layer.”
Bouncing two files”You may only edit src/auth/login.ts. All other files are read-only.”
Same flaky test failing”Stop running this test. Mock the time-dependent dependency, then move on.”
Re-running failed command”The last command exited non-zero. Read the error, don’t re-run blindly.”

Step 3: For flaky tests, stabilize the test first

Don’t let the agent loop on a flaky signal. Stabilize:

# Run 5 times — is it stable?
for i in {1..5}; do pnpm test -- --testNamePattern="login flow"; done

If 2+ fail, mock the source of nondeterminism:

// vitest setup
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));

Then resume the agent with the now-stable test.

Step 4: Open a fresh session with full context

If nothing above works, the last lever is context reset:

1. Copy current file contents (not the diff).
2. New session.
3. Restart:
   Goal: [one-sentence]
   Current code: [paste full file]
   Failing test/error: [paste verbatim]
   Constraints: don't touch tests, only edit src/X.ts.
   Print plan first; wait for approval before editing.

Fresh context isn’t polluted by old failure logs — usually succeeds first try.

Step 5: Set iteration caps

Prevent next loop. Add to CLAUDE.md:

## Agent behavior constraints

- Maximum 5 build/test iterations per task
- If failing after 3 iterations, stop and report
- Do not edit the same block in the same file more than 3 times
- After 3 retries of any tool call, stop and ask

Cursor uses .cursorrules, Codex uses AGENTS.md — same idea.

Step 6: Force replan on stuck plans

If the agent is on step 1 forever:

Stop. The current plan is failing. Don't continue.
Print:
1. Why step 1 isn't working
2. Two alternative approaches
3. Recommend one

Wait for my approval before continuing.

This forces the agent out of the failed plan instead of grinding on it.

Prevention

  • Set iteration caps in CLAUDE.md so the loop has a built-in exit
  • Isolate flaky tests into a flaky.test.ts so agents never iterate on unstable signals
  • Force replan after 3 consecutive failed attempts on the same step
  • Give explicit completion criteria — not “fix login” but “pnpm test -- auth exits 0”
  • Inspect the agent’s action trace, not just the final output — loops show in the trace
  • When a loop appears, open a fresh session rather than recovering a polluted one

Tags: #Troubleshooting #Claude Code #Debug #Agent loop