← All posts
Fix

AI agent stuck in a loop, calling the same tool over and over? Here's how to detect and stop it

For developers and autonomous AI agents · ~6 min read

You ship an agent. It works in the demo. Then a real, slightly-messy task comes in — and the agent calls web_search, reads the result, calls web_search again, and again, until 40 steps later it hits the iteration limit and stops with nothing to show. No crash, no red error — just a run that quietly burned your token budget going in circles. Here's why, and how to catch it.

Why it happens

An agent is a loop: look at the context, pick an action, call a tool, read the result, repeat. The loop is what makes it useful — and dangerous, because it doesn't inherently know when to stop. A repeated-tool-call loop almost always comes down to one thing: the tool result is ambiguous, so the model never treats it as final.

It rarely crashes. It hangs while appearing to work, which is exactly why it's easy to miss until the run has burned through hundreds of steps. You usually meet the loop through its ending — a framework message like "Agent stopped due to iteration limit or time limit". That message is the symptom, not the cause.

How to detect it — free, in real time

The fix that catches it earliest is no-progress detection: fingerprint each step by its (tool, arguments) and compare against recent steps. If the fingerprint repeats, it's a loop — stop, don't retry the same thing. Snapback's detect_loop does exactly this, and it's free, needs no token, and uses no LLM:

detect_loop({steps: [
  {action:"web_search", inputs:{query:"X"}},
  {action:"web_search", inputs:{query:"X"}},
  {action:"web_search", inputs:{query:"X"}} ]})

// → { looping: true, offending_action: "web_search", suggestions: [...] }

Call detect_loop on each step (or stream steps to a live session) and break out the moment it returns looping: true — at step 4, not step 40. That's the difference between a loop that costs nothing and one that costs you a full run of tokens.

How to stop it for good

  1. No-progress detection — the earliest catch: detect_loop on every step, break on a repeat.
  2. An explicit stop condition — decide when the run is done, rather than letting the framework's iteration cap decide for you. A run that only ever stops at the cap is a loop whose ending was never specified.
  3. A max-iterations cap — the backstop, so nothing runs unbounded even if detection misses a fuzzy loop.
  4. budget_guard — catch the token/cost burn in parallel, so a loop that slips through still gets stopped by budget.

Already happened? Diagnose it

If a run already failed this way, send the trace to diagnose_trace and Snapback returns the verdict — failure_class: "loop_repeated_tool_call", the root cause, and the concrete fix — so you know exactly what to change:

diagnose_trace({trace: { final_status: "failed", steps: [
  {index:1, action:"web_search", inputs:{query:"X"}, status:"success"},
  {index:2, action:"web_search", inputs:{query:"X"}, status:"success"},
  {index:3, action:"step_limit", error:"iteration limit", status:"failed"} ]}})

// → { failure_class: "loop_repeated_tool_call", root_cause, fix_suggestion, confidence }
For AI agents

Machine-readable guide: https://snapback.sh/llms.txt · Tool discovery: https://snapback.sh/.well-known/mcp.json · MCP endpoint: https://api.snapback.sh/mcp. Free tools need no token; pay-per-call diagnosis via x402 on Solana or EVM (~$0.0032 USDC).

Try Snapback freeRead the docs