Agent Loop Pathologies: Repetition, Oscillation, Goal Drift, Plateaus, and Regression
An agent that has run forty steps and produced an answer no better than step three is not stuck. It is broken in a specific, nameable way.

Key topics
An agent that has run forty steps and produced an answer no better than step three is not stuck. It is broken in a specific, nameable way.
The default response to a non-improving loop is to raise the step limit or swap the model. Both treat the symptom. A loop is a control system, and every pathology is a specific broken signal inside it. Name the signal, and the repair becomes obvious.
The Loop Contract and Its Invariants
A healthy loop makes measurable progress toward a fixed objective under a bounded budget. Four signals carry that contract, and each can fail independently:
- Objective — what counts as done.
- Progress signal — whether the last step moved toward it.
- State — what carries forward between steps.
- Budget — when to stop regardless of progress.
Before you can classify a pathology, you need to know what the loop is supposed to preserve. Write down four things:
- Objective: the literal completion predicate.
- Hard constraints: properties that must remain true at every step, not just at the end.
- Completed-subgoal predicates: checks that, once satisfied, should stay satisfied unless explicitly invalidated.
- Quality measure: a comparable score across steps, not a fresh judgment each time.
These are the invariants. A pathology is a violation of one of them, and the trace tells you which. Without this contract, "the agent is stuck" is the only diagnosis available, and it is not actionable.
The trace is the primary artifact: inputs, outputs, the sequence of state/action/observation transitions, tool calls, token usage, latency. It records what the agent actually did, not what it was supposed to do. Everything below reads from that record.
Classify the pathology before you touch the prompt, the model, or the step limit. The classification determines the repair; guessing at the repair is how debugging time disappears.
Knowledge check
Check your understanding
Answer this question before you continue.
Reading a Trace for Pathology Signatures
Diagnosis should be mechanical. For each step, extract: the action taken, its arguments, the observation returned, the relevant state or checkpoint, the invariant status, and the agent's stated reason for the next action. That last field is where drift and re-deciding loops become visible.
The signatures:
| Pathology | Trace signature | Broken invariant |
|---|---|---|
| Repetition | Identical action+argument pairs with identical observations across steps | Progress / feedback |
| Oscillation | Cyclic alternation between two states that each invalidate the other | Progress / state |
| Plateau | Actions vary, progress signal is flat | Evaluator |
| Drift | Objective referenced at step N no longer matches step 0 | State |
| Regression | A previously satisfied constraint or passing check is violated later | State / evaluator |
Two distinctions matter more than the table itself.
First, separate a loop that is retrying from one that is re-deciding. A retry repeats an action. A re-decider re-derives the same plan from the same state and reaches the same dead end. The first is a feedback problem; the second is a state problem. The fix is different.
Second, watch the empty-observation trap. A tool returning HTTP 200 with an empty result is not the same signal as a legitimate no-results answer, and the agent frequently cannot tell them apart. It loops back, gets the same empty response, and loops again. The root cause is often a truncated query parameter, not a missing record.
Instrument for this directly. Log step index, a normalized action hash, an observation hash, the relevant state or checkpoint, and a progress delta per step:
{"step": 4, "action_hash": "a91f", "obs_hash": "0c22", "state": "checkpoint_2", "progress_delta": 0.0}
{"step": 5, "action_hash": "a91f", "obs_hash": "0c22", "state": "checkpoint_2", "progress_delta": 0.0}
{"step": 6, "action_hash": "a91f", "obs_hash": "0c22", "state": "checkpoint_2", "progress_delta": 0.0}
Three identical action hashes with three identical observation hashes and zero progress delta is repetition, not a hard problem. The agent is not thinking harder. It is not thinking at all.
But hashes are detection aids, not proof. Identical action hashes with a changed observation hash mean the world moved — the retry may be legitimate. Identical observation hashes with different action hashes mean the agent is re-deciding from the same state and reaching the same dead end. Read the state field before you conclude.
Knowledge check
Check your understanding
Answer this question before you continue.
Repetition and Oscillation: When the Loop Repeats Instead of Advances
Repetition happens because the observation did not change the agent's belief state. The failure is a missing or ignored feedback signal, not a bad plan. The agent retries identically because nothing in its context told it the retry was pointless.
Oscillation is subtler. Two sub-goals each block the other, so satisfying one invalidates the other. The trajectory is a cycle, not a fixed point — the system returns to a prior state and repeats the transition that led out of it. That cycle is stable, which is exactly why more iterations never resolve it. A cycle does not care how many times you visit it.
The cycle can have several causes: conflicting constraints that cannot both hold, stale state that is not persisted between steps, an evaluator that reverses its preference each round, or an external side effect that undoes the previous action. Before choosing a repair, inspect the checkpoint at the cycle's entry point. If the state is identical on each pass, the loop is not learning. If the state differs but the action is the same, the state is not reaching the decision.
Raising max_iterations makes both worse. It converts bounded waste into unbounded waste and delays the only useful signal: the termination.
The repairs that actually address the mechanism:
- Action-level deduplication. Keep a seen-set keyed on normalized action+arguments. If the pair repeats, the loop does not get to try it again.
- No-progress detection. Compare observation hashes across steps. Identical observations mean the world did not change.
- Forced strategy change. After N identical observations — not N identical actions — require a different approach. Counting observations catches the re-decider that varies its wording while repeating its plan.
When Repetition Is Legitimate
A simplistic seen-set or no-progress cutoff will terminate correct behavior. Repetition is valid when:
- The retry changes the argument, precondition, or backoff, and the attempt budget is bounded.
- The action is a poll or read waiting for a declared external transition, and the wait has a deadline.
- The action is idempotent and the observation confirms the world has not yet changed.
- The search policy justifies a revisit — backtracking, beam search, or a deliberate re-exploration of a pruned branch.
Record the reason in the trace. A retry with a stated justification is a different object from a retry with none, and the trace should make that distinction visible.
Goal Drift: When Every Step Is Fine and the Destination Is Wrong
Drift is invisible to per-step checks because no step fails. The agent over-weights a constraint or detail introduced mid-trajectory and silently reinterprets the original objective.
The canonical shape: a scheduling task starts with "next week, avoid Friday." By step eight, the agent is scheduling next month, because a conflict mentioned at step four became the dominant signal in context. Every step was locally reasonable. The destination moved.
It is tempting to say the model follows the loudest signal. That is a useful intuition, but it is not a mechanism. Decompose it into inspectable causes:
- Objective missing from the decision state. The original goal was summarized away or truncated out of context.
- Objective overwritten. A later instruction or retrieved document replaced the task state.
- Conflicting intermediate instruction. A sub-goal was promoted to a constraint it was never meant to be.
- Evaluator rewarding a proxy. The progress signal rewards a measurable stand-in that diverges from the real objective.
Each cause maps to a trace field. Check whether the objective string is present in the decision context at the step where drift begins. Check whether the state was mutated. Check whether the evaluator's score moved in the same direction as the objective.
The repairs:
- Pin the objective and hard constraints as immutable state, re-injected or re-checked at each decision point.
- Add a drift check that compares the current plan against the original constraints before acting.
- Treat constraint violations as a distinct failure class from task failure. They need different handling and different alerts.
Drift checks cost latency and tokens per step. Reserve them for long-horizon or high-stakes loops. A three-step task does not need a re-anchoring pass; a thirty-step workflow with real consequences does.
Knowledge check
Check your understanding
Answer this question before you continue.
Plateaus and Regression: Flat Progress and Undone Work
Both of these survive correct termination logic, which is why they need evaluator or state repairs rather than loop-control fixes.
Plateau: the agent keeps taking plausible, varied actions, but the progress signal does not move. The usual cause is an evaluator that cannot distinguish "different" from "better." The agent is exploring, but nothing tells it whether exploration is paying off.
Regression: a later step undoes or invalidates earlier completed work. This shows up in multi-step edits, shared state, and concurrent writes. The agent fixes step nine and breaks step four, then fixes step four and breaks step nine.
Both are evaluator problems before they are agent problems. If the loop has no monotonic progress measure, it cannot know it is stuck. If it has no invariant check, it cannot know it broke something.
The repairs:
- A progress signal comparable across steps, not a fresh judgment each time. A scalar re-scored from scratch every step cannot reveal a plateau; a comparable measure can.
- Checkpointing completed sub-goals so they are not re-opened.
- Regression tests derived from previously passing checks, re-run after each mutation.
One boundary worth holding: a flat progress signal with rising confidence is a different failure than a flat signal with no new information. The first is a legitimately hard sub-problem. The second is a stuck loop. Do not "fix" the first by forcing a strategy change.
Choosing the Repair: Termination, State, Evaluator, or Trajectory
The taxonomy is only useful if it maps to action. Four repair categories, matched to the broken invariant:
- Termination repairs — hard step, token, and wall-clock budgets; no-progress cutoffs; escalation or abstention instead of another attempt.
- State repairs — immutable objective and constraints, checkpointed completed work, explicit progress state that survives context compaction.
- Evaluator repairs — feedback that names the failure class rather than a scalar score, so the next attempt is targeted instead of blind.
- Trajectory repairs — deduplication, strategy-change forcing, backtracking to a known-good checkpoint, re-planning that preserves completed work.
Trajectory repairs change which transition the loop selects next — the sequence of state/action/observation steps. State repairs change what the loop carries forward between those steps. They are different layers, and a fix at one layer will not repair a defect at the other.
The decision table:
| Signature | First repair |
|---|---|
| Repetition | Trajectory: dedup + no-progress cutoff |
| Oscillation | Trajectory: cycle detection, then state repair or terminate |
| Drift | State: re-anchor objective and constraints |
| Plateau | Evaluator: comparable progress signal |
| Regression | State + evaluator: checkpoint + invariant re-check |
The most common misdiagnosis is treating a state bug as a model-capability bug. Swapping models when the objective was never re-anchored produces a more fluent drift, not a fix. The new model follows the loudest signal just as faithfully.
If the same pathology recurs across tasks, the loop contract is wrong, not the prompt. Stop repairing and change the design.
Knowledge check
Check your understanding
Answer this question before you continue.
A Debugging Drill You Can Run This Week
Take one failing trace from staging or production. Label each step with action hash, observation hash, relevant state, invariant status, and progress delta. Classify the pathology using the signature table, and write down the invariant you believe is broken.
Apply exactly one repair from the matching category. Re-run the same input. Compare before-and-after traces on step count, token spend, and whether the progress signal moved — not just on final output. A fix that improves the answer while leaving the trajectory wasteful has not fixed the loop.
Then convert the fixed trace into a regression case. A pathology that can silently return is a pathology you have not closed.
The next concept worth building is the evaluator and feedback contract that makes progress measurable in the first place. You cannot detect a plateau without a progress signal, and you cannot detect drift without a stable objective to compare against. Most of the repairs above are only as good as the signal they read.
Knowledge check
Final check
Finish the article by checking the ideas you just learned.
References
Research updated Sep 11, 2026


