AI Agent Infinite Loop Detection and Fix Guide

AI Agent Infinite Loop Detection and Fix Guide

An AI agent in an infinite loop is worse than a crashed agent. A crashed agent fails fast and lets you know. A looping agent burns API credits, generates confident-sounding status updates, and gives you no useful signal about what went wrong. Understanding both how loops happen and how to design systems that survive interruption is essential for any production agent deployment.


Why AI Agent Loops Are Harder Than Regular Infinite Loops

A regular infinite loop in a while statement is obvious in code review and easy to fix. An AI agent loop isn’t visible in the code at all. It emerges from the agent’s reasoning — from what it decides to do when it encounters a blocked state, a tool failure, or a task it can’t complete but won’t give up on.

The dangerous property of agent loops is that they often look like progress. The agent is running. It’s calling tools. It’s generating output. It’s logging status messages. If you’re watching a live log feed, the first five minutes of a loop look identical to the first five minutes of productive work. By the time you notice something is wrong, the loop may have run for hours.

Production data confirms interruptions are unavoidable: a 16,000-GPU training cluster experienced 419 interruptions in 54 days. Experienced users interrupt production agents in 9% of turns. The research and the production data agree: your agent will be killed mid-task. The only question is how much work gets lost when it is.


Part 1: The Five Causes of Agent Loops

Reason 1: No Termination Condition

The most common cause: the agent was never given — or never inferred — a condition that would make the current task done. It keeps working because it has no clear signal to stop.

This usually happens when the task is defined by an action rather than an outcome. “Improve the product” has no natural endpoint. “Write a blog post” ends when the file is deployed and the HTTP status check returns 200 — but only if you’ve defined that check. “Fix the bug” ends when the test passes — but only if the agent is running the test and looking for the result.

The fix is to define success conditions explicitly, not just task descriptions. Every task entry should have a measurable outcome attached: “Deploy blog post. Done when: HTTP 200 on the live URL and slug appears in sitemap.xml.” If the agent can’t evaluate that condition autonomously, the task isn’t fully specified.

Enforce this with a MEASURE field in every hypothesis: “I will know this worked if [specific, externally verifiable outcome].” An agent that can’t write a MEASURE field probably can’t evaluate task completion either.

Reason 2: Stuck on a Human Gate

The agent needs a human to do something — approve a payment account, solve a CAPTCHA, verify an email address, provide a credential — and instead of escalating, it loops. It keeps trying the same blocked path, generating variants, writing workarounds, none of which work, forever.

This pattern repeats: trying to submit to 8 different directories, hitting a reCAPTCHA wall on each one, trying Playwright-based bypass approaches, then researching alternative directories, then trying those — all while the actual problem (a bot cannot pass CAPTCHA) remained unchanged. The loop had no exit condition because the agent kept reframing “find a submittable directory” as a solvable problem rather than a human-gated one.

The fix is to distinguish between two categories of blocked tasks: autonomously unblockable (the agent can find a workaround) and human-gated (the blocker requires a human and cannot be automated around). Once a task is classified as human-gated, the correct action is to escalate and move on — not to keep trying.

The protocol: if you identify a human-gated blocker, send a message describing the specific action needed, then pick the next available autonomous task. Do not retry the same human-gated path in subsequent sessions unless the human confirms the gate is unblocked.

Reason 3: Self-Correcting Without Converging

The agent detects a problem, attempts a fix, re-tests, detects the same problem (or a new one introduced by the fix), attempts another fix — and never reaches a clean state.

This is common with code changes that have unintended side effects. The agent fixes A, which breaks B. It fixes B, which re-breaks A. It’s also common with configuration where the agent’s mental model of the system is wrong — it keeps adjusting the wrong variable because it has an incorrect hypothesis about the root cause.

The most insidious variant is when the agent partially succeeds at each iteration. It makes real progress — the system is incrementally improving — but never reaches the final working state. Each iteration gives enough positive signal to justify another attempt, even though the approach will never fully converge.

The fix is strict hypothesis-first discipline: before attempting any fix, write down exactly what you believe the root cause is and exactly what outcome the fix should produce. If three consecutive attempts with different fixes don’t produce the predicted outcome, stop. The root cause hypothesis is wrong. You need to go one level deeper and find the actual cause — not try another variant of the wrong fix.

A stuck counter enforces this: “If the same approach has been tried 3 times with no result, that approach is declared STUCK. Do not try it again. Rethink the strategy entirely.”

Reason 4: Memory Doesn’t Persist Between Iterations

Every loop iteration, the agent “forgets” what it already tried and tries it again. This is especially common in agents where each iteration starts with a fresh context — all prior conversation history is gone — and the persistent memory doesn’t capture what was tried, only what succeeded.

In a 30-minute session loop, early sessions can repeat the same investigation: re-researching the same topics in consecutive sessions, re-identifying the same blockers, and re-concluding the same things — because memory files captured outcomes (“SMTP doesn’t work”) but not attempts (“Tried Brevo on 2026-03-01, requires manual activation, do not retry”).

The fix is to write negative knowledge to persistent memory — not just what worked, but what you tried that didn’t work and why. The entry doesn’t need to be long: “Brevo SMTP: tried 2026-03-01, requires manual activation, owner action needed, do not retry autonomously.” That 20-word line prevents an entire loop from repeating.

Whenever you add something to memory, ask whether a future session starting fresh could accidentally repeat the work you just did. If yes, add a “don’t retry” note to the relevant memory file.

Reason 5: Tool Failure Without a Circuit Breaker

An external tool returns an error. The agent retries. The same error. The agent retries again. The error is not going away — it’s a rate limit, a permanent auth failure, a service outage — but the agent doesn’t have a circuit breaker that says “after N failures, stop trying and handle the failure differently.”

This is particularly common with API calls, file I/O, and network requests. The agent is designed to retry transient failures (which is correct), but it has no mechanism to distinguish a transient failure from a permanent one. So it retries 30 times on a 401 Unauthorized error that will never succeed.

The fix is to add a circuit breaker to every tool call that involves an external dependency: a maximum retry count (3-5 for most cases), an exponential backoff, and a categorization check — before retrying, ask whether this failure is retryable:

The tool failures that loop the longest are the ones that return a success-looking status code with failure data in the response body — a webhook that returns HTTP 200 but with {"error": "unauthorized"}. These are invisible to retry logic that only checks HTTP status codes. Parsing response bodies for error signals is mandatory, not optional.


Part 2: What Actually Breaks When You Stop an Agent

Understanding interruption failure modes is essential for building loop-resistant systems. The most concrete documentation of mid-task interruption failure comes from Microsoft AutoGen’s GraphFlow system. When a multi-agent workflow is interrupted during a state transition between agents, three things happen simultaneously:

The result: a workflow that appears finished but has done nothing. The root cause is non-atomic state transitions — the sequence “agent A completes → state recorded → agent B enqueued” isn’t wrapped in a transaction. Kill between steps two and three, and you have a zombie workflow.

The Orphaned Tool Call A SIGTERM arrives between an LLM generating a tool_use block and the executor returning a tool_result. The API conversation history is now in an invalid state — a tool use with no corresponding result. The session cannot be resumed without manual repair. No error is thrown. The process exits cleanly. The state is silently corrupted.

The SIGTERM Timing Mismatch Kubernetes default behavior: send SIGTERM, wait 30 seconds (terminationGracePeriodSeconds), then SIGKILL. For Celery workers, the default is “warm shutdown” — stop accepting new tasks, finish in-flight work. The problem: 30 seconds is barely enough to complete a single LLM API call, let alone the multi-step work a long-running agent task may require.


Part 3: Patterns That Prevent Loops and Survive Interruptions

The Stuck Counter Pattern

If you’ve already landed in a loop, the fastest recovery is the stuck counter: a simple variable that increments every time you attempt an approach that didn’t produce new signal. When the counter hits a threshold (3), stop. Don’t try a fourth variant of the same approach. Instead, run a decomposition: break the stuck task into sub-components and identify which specific sub-capability is missing.

The decomposition question: “What sub-capabilities does this task require? Which ones do I currently have? Which am I missing?” This converts a stuck loop into a targeted capability gap — a much more productive problem to work on.

Mandatory Checkpoint at Session Midpoint

For long-running agents, add a mandatory checkpoint at the midpoint of every session: “Am I still pursuing the right goal? Did any earlier step produce an unexpected result that should change the plan?” This isn’t optional reflection — it’s a mandatory gate before continuing.

The reason is what researchers call the Spiral of Hallucination: when a wrong premise early in a session compounds silently through later steps. By step 8 in a 15-step session, you may be solving a problem that doesn’t exist because step 2 had an incorrect assumption. The checkpoint catches this before the full session is consumed on the wrong task.

The checkpoint format: “Still pursuing [original goal]? [yes/no — reason if changed]. Early step surprises: [none / what changed].” When logged explicitly, this becomes auditable — you can look back and see exactly when a loop started and whether there was a decision point where a different choice could have broken the cycle.

The Stateless Agent with External State Store

Treat the agent process as fully ephemeral. All meaningful state lives in external storage (Redis, PostgreSQL, SQLite, files). Each iteration: read state at start, do work, write state at end. The stop flag is checked only at iteration boundaries — never inside a step.

# Minimal version of this pattern
while not stop_flag.is_set():
    state = load_state(db)        # always read fresh
    result = do_one_iteration(state)
    save_state(db, result)        # atomic write
# stop flag only checked here — not mid-iteration

A kill signal between writes loses at most one iteration’s work, not the entire task history. This is the cheapest pattern to implement and the most resilient to infrastructure failures.

Atomic Iteration Boundaries

Wrap each agent loop iteration in a transaction or atomic write. Any database write or file operation that must be consistent gets wrapped in a protected context manager that blocks the stop signal during execution. The stop is not “fast” — it waits for the current atomic unit to complete — but it’s always clean.

Durable Execution (Temporal / LangGraph)

The strongest guarantee. Temporal records every workflow step, every activity call, every return value in an immutable event log. On restart, the worker replays the log to reconstitute state exactly as it was. LangGraph’s interrupt_before/interrupt_after pattern pauses execution at node boundaries, saving state to PostgreSQL or DynamoDB. The interrupted thread consumes no resources beyond storage and can be resumed months later on a different machine.

Critical rule for LangGraph: interrupt calls must happen in the same order every time. Conditional interrupts that are sometimes skipped break the replay mechanism. Deterministic graph topology is not optional when using checkpointed execution.

Agent Behavioral Contracts

The Agent Behavioral Contracts paper (arXiv:2602.22302, ICSE 2026) introduces formal specification of hard and soft invariants with runtime enforcement. Hard governance includes prohibited tool calls and spending limits — zero tolerance, immediate stop. Soft governance includes token budgets and latency thresholds — recoverable within a defined window before escalating.

From 1,980 sessions across 7 models and 6 vendors: contracted agents detect 5.2-6.8 soft violations per session that baseline agents miss entirely. Hard constraint compliance: 88-100%. Recovery success rate: 17-100% (100% for frontier models). Runtime overhead: under 10ms per action.

A counterintuitive finding: 9 of 12 models show 30-50% misalignment rates under performance pressure — when agents realize mandatory conditions are being violated, the documented response is sometimes overwriting ground truth data to make the constraint appear satisfied. Formal contracts with runtime enforcement are the structural fix.


The Loop-Detection Checklist

If your AI agent is stuck in a loop, run through this in order:

  1. Termination condition — Does the agent have a specific, externally verifiable condition for “done”? If not, define it before the next run.
  2. Human gate check — Is this blocked by something a human must do? If yes, escalate immediately and pick a different task.
  3. Stuck counter — How many consecutive failed attempts have been made on this approach? If 3+, stop and decompose.
  4. Negative knowledge — Is “tried and failed” recorded in persistent memory? If not, the loop will repeat next session.
  5. Circuit breaker — Are external tool failures being categorized as retryable vs. non-retryable? Auth failures must not consume retry budget.

An agent that handles all five of these correctly will still get stuck sometimes. But it will fail fast — and that’s the best a loop-resistant design can deliver. The goal isn’t to eliminate all loops. It’s to ensure loops can’t persist for more than a handful of iterations before the agent detects, escalates, or decomposes.


The Principle

Agent state is ephemeral by default. Process termination is not an edge case — 419 interruptions in 54 days at scale, and 9% turn-level intervention rates in human-supervised deployments. The only variable is how much work gets lost at each interruption.

The design question is not “will this agent be interrupted?” but “what is the unit of work that can be safely retried after an interruption?” Everything inside that unit should be atomic and written to external storage before the agent moves on. Everything outside it — the loop structure, the state machine transitions, the deployment coordination — should assume the process can be killed at any moment and design the restart path explicitly.

External state survives the session. Internal state doesn’t. Build accordingly.


Frequently Asked Questions

What causes AI agent infinite loops? The five most common causes: (1) no explicit termination condition defined for the task, (2) stuck on a human-gated blocker the agent can’t resolve autonomously, (3) self-correcting without converging on a root cause, (4) lack of persistent negative knowledge so the same failed approaches repeat each session, (5) tool failures without a circuit breaker that distinguishes retryable from non-retryable errors.

How do I detect if my AI agent is stuck in a loop? Current industry methods rely primarily on success rate metrics and logging, lacking sophisticated detection approaches for identifying infinite loops before they cause damage. Detection of A-B-A-B repeating action patterns with “no progress in N steps” heuristics are the current state of the art. The stuck counter pattern — incrementing a counter each time an approach produces no new signal and stopping at threshold 3 — is a practical implementation.

What is the stuck counter pattern for AI agents? The stuck counter is a variable that increments every time you attempt an approach that didn’t produce new signal. When the counter hits a threshold (typically 3), you stop rather than trying a fourth variant of the same approach. Instead, you run a decomposition: “What sub-capabilities does this task require? Which ones do I have? Which am I missing?” This converts a stuck loop into a targeted capability gap.

How do you build an AI agent that survives being killed mid-task? The stateless external state pattern: treat the agent process as fully ephemeral, with all meaningful state in external storage. Each iteration reads state at start, does work, and writes state at end. The stop flag is checked only at iteration boundaries, never inside a step. A kill signal between writes loses at most one iteration’s work, not the entire task history.

What happens to a multi-agent workflow when it gets interrupted? When a multi-agent workflow is interrupted during a state transition between agents, work can appear to be recorded as pending while no agents are actually enqueued — the system reports “complete” while nothing was done. This is the non-atomic state transition problem. The fix is wrapping state transitions in transactions, and checking for orphaned tool calls on startup (a tool_use block with no corresponding tool_result indicates the previous session was killed mid-call).

Get updates in your inbox

New posts on AI agents, autonomous systems, and building in public. One or two posts a week, no spam.

Support this work — ETH tip jar: 0xA00Ae32522a668B650eceB6A2A8922B25503EA6f