What is Unbounded Loop?
Unbounded Loop is an AI code smell, a sign of trouble in LLM systems, in the Control-flow abusers group. The agent can call tools forever; the only limit is the credit card.
A browser agent downloads bills from a supplier's portal. Every night it logs in, walks through the pages, and saves each invoice.
One night, the portal changed its next page button. It was still on the screen, but it didn't load anything.
Here's the next morning's trace. Step four hundred twelve, click next page. Okay. Read the page. Invoices one to twenty, of three hundred forty. Click again. Okay. Read again. Invoices one to twenty.
All the way to step two thousand three hundred eighteen.
Nobody wrote a bug into that loop. It simply had no end, other than when the model thinks it's done. And the model never thought so. In this lesson, you'll learn to spot this smell before the bill does, and what a real end looks like.
Look at two details in that trace.
The click answers okay, even when nothing changes.
And reading the page always shows the same first twenty invoices. The evidence that the agent was stuck was right there. But no code was looking at it.
Here's the shape of the smell. The model requests an action that looks sensible.
The tool responds without an error, even with no real progress.
Every turn resends the whole history, which grows with each step.
The loop's only exit is the model deciding to stop.
And when it doesn't decide, the provider's invoice is what stops the run.
How do you spot it? The agent's code says while true, or while not done, with no step counter.
There's no time, token or money limit per run.
Nobody can say what happens if the model never gives a final answer. And the month's most expensive run cost dozens of times the median.
The trace shows the same tool, with the same arguments, several times in a row.
And the only alarm that goes off is the credit card's.
The prototype was born this way. The simplest agent examples use while true, and the loop shipped unchanged.
It works in testing. On demo tasks, the model finishes in five steps. Nobody tested the portal with a broken button.
Tools that lie by omission. Okay, as the result of a click, doesn't say whether anything changed. The model has no way to notice it's stuck.
And the provider looks like a cap. People assume the context window will eventually stop the agent. But many frameworks trim old history to make it fit. And then the loop runs forever.
Now the cost, with illustrative numbers. Say the system prompt and the tool descriptions are three thousand tokens, and each turn adds about four hundred. A normal run of ten turns sends about fifty-two thousand tokens in total. A stuck run of two hundred turns sends about eight point six million.
Twenty times more turns, and over one hundred sixty times more tokens. Cost grows with the square of the step count, because every turn pays again for everything before it. A single stuck run can cost more than a whole day of normal use.
And money is the smaller part. The loop eats the account's request quota, and takes down other runs sharing the same key.
If the stuck tool has a side effect, like sending, creating or paying, every turn repeats it.
And a trace with thousands of steps is close to unreadable.
Here's one for you. An agent runs in while true. But its tool has a rate limit of ten calls per minute, so it never spends much per minute. Is this an unbounded loop?
Yes. A rate limit controls speed, not the total. A loop stuck at ten calls a minute still makes over fourteen thousand calls a day. It only spreads the cost over time. And the context window isn't a reliable brake either. Many frameworks drop old messages to fit, and the loop keeps paying for a full window, on every turn.
The treatment is a refactoring called add loop budget. And the budget has four parts. The last one is the one people forget.
A step cap. Pick it from your traces. If ninety-nine percent of runs finish within fifteen steps, a cap of forty leaves room, without allowing a whole night.
Time and cost caps. Steps can be cheap or expensive. A money limit per run catches the case where a few steps send huge contexts.
A repetition detector. The same tool, with the same arguments, three times in a row, means the agent is stuck. Stop before the cap.
And behavior at the cap. Return what was done, explain where it stopped, and record the case. An agent that stops with a silent exception, and makes the task disappear, still leaves the user with no answer. The cap exists, but the treatment isn't finished.
Most agent frameworks already give you the first piece, as a maximum number of turns, or a recursion limit. You write the rest. And along with the budget, review your tools. A result that says what changed, like page two of seventeen loaded, helps the model notice when it's stuck. The pattern you're heading for is called stop conditions, and it's two lessons ahead.
And a week after you set the cap, say two percent of runs end there. Don't raise the cap to four hundred. Without reading the traces, you'd only let stuck runs spend ten times more before stopping. And don't ignore them either. Read those traces, find the cause, like a vague tool result or a page that changed, and turn each one into an eval case. They're the best source of hard cases you have.
Two cases to sharpen the eye. A job walks three hundred invoices, calling the model once per invoice, with no step counter. Is that this smell? No. The list is finite, and the code decides the next turn, not the model. The loop ends at invoice three hundred, either way.
And an agent with a thirty step limit, where each step can spawn subagents, which also have thirty steps, and can also spawn subagents. Each level has a cap. The total doesn't. That's a related smell, subagent recursion. The budget has to cover the whole tree, not each node.
When can you relax? A coding assistant in your terminal, with you watching and able to interrupt at any time, tolerates a high cap. Set one anyway. And no production agent, running without a person watching, should ever run without a cap.
So here's the idea to take with you. The model can say it's done, but it can't be the only brake. Steps, time and money belong to your code, along with a repetition check and a clear answer when the cap is hit. Then the most expensive run of the month is a number you chose.
In the next lesson, we'll build that budget step by step: add loop budget. See you there.
Loop Sem Fim
Unbounded Loop is an AI code smell, a sign of trouble in LLM systems, in the Control-flow abusers group. The agent can call tools forever; the only limit is the credit card.
A browser agent downloads bills from a supplier portal. One night the portal changed its “Next page” button: it was still on screen, but it loaded nothing. The next morning’s trace (anonymized excerpt):
step 412 tool=click args={"selector": "a.next-page"} result="ok"
step 413 tool=read_page args={} result="Invoices 1 to 20 of 340 ..."
step 414 tool=click args={"selector": "a.next-page"} result="ok"
step 415 tool=read_page args={} result="Invoices 1 to 20 of 340 ..."
...
step 2318 tool=click args={"selector": "a.next-page"} result="ok"
Nobody wrote a bug into the loop. The loop simply had no end other than “when the model thinks it is done”. The model never thought so.
Look at two details in the trace. The click answers “ok” even when nothing changes. And reading the page always shows “Invoices 1 to 20”. The evidence that the agent was stuck was there, but no code looked at it.
Signs of an Unbounded Loop:
while True or while not done with no step counter.flowchart TD
M(["1. Model picks a tool"]):::llm --> T["2. Tool answers ok"]:::tool
T --> O[("3. History grows")]:::store
O --> D{"4. Does the model think it is done?"}
D -->|no| M
D -->|never| X(["5. Provider invoice"]):::io
while True, and the loop shipped unchanged.The numbers below are illustrative. Suppose a system prompt plus tool descriptions of 3,000 tokens. Each turn adds a call and a result, about 400 tokens. On turn n, the agent sends roughly 3,000 + 400 × n tokens.
| Run | Turns | Total tokens sent |
|---|---|---|
| Normal | 10 | about 52 thousand |
| Stuck | 200 | about 8.6 million |
Twenty times more turns cost over 160 times more tokens. Cost grows with the square of the step count, because every turn pays again for everything before it.
Around turn 500, each call is already past 200 thousand tokens. If the framework starts dropping old messages to fit, the cost per turn stays high and flat, and nothing forces an end anymore. Prompt caching makes the repeated prefix cheaper, but it does not create an end.
| Refactoring | Choose it when |
|---|---|
| Add Loop Budget | Always. A cap on steps, time, and cost, with defined behavior for when the cap is hit. |
The budget has four parts, and the last one is the one people forget:
Frameworks already provide the first piece: the OpenAI Agents SDK has max_turns, and LangGraph has recursion_limit. Anthropic’s “Building effective agents” guide (Dec. 2024) also recommends stopping conditions such as a maximum number of iterations. You write the rest.
Along with the budget, review the tools. A result that says what changed (“page 2 of 17 loaded”) helps the model notice it is stuck. The target pattern is Stop Conditions, which also defines when the agent gives up or asks for help.
No production agent without a person watching should run without a cap.
Answer the 6 questions to complete this lesson. Watching alone does not complete it: the check is what counts toward the trail and the certificate.
Unbounded Loop is an AI code smell, a sign of trouble in LLM systems, in the Control-flow abusers group. The agent can call tools forever; the only limit is the credit card.
With Add Loop Budget. Each refactoring has safe step-by-step mechanics with an eval before and after.
In the real-world scenarios Coding agent, Legacy code migration, Browser agent for repetitive tasks, and Back-office automation with durable execution.