The agent looped on a broken tool all weekend. A bigger budget wouldn't have helped.
Someone posted the kind of Monday that everyone building agents is one bug away from: they woke up to a massive API bill because a LangGraph agent had spent the entire weekend looping on a broken tool. The question they asked was the right one — how do you prevent this? — and the replies are a near-perfect map of how people reach for the wrong brake first.
Every static cap is a snooze button
Almost every answer named a static limit: raise the recursion limit, set a token budget, cap the number of turns. They’re not wrong that a cap helps. But as one commenter put it, a static cap “just delays the same burn.” A broken tool doesn’t care that your ceiling is 25 instead of 10 — it hits the new ceiling too, just later and more expensively. You didn’t stop the loop. You gave it a longer runway.
There’s a subtler failure underneath that one: a blunt budget can’t tell a broken tool from a legitimately long job. A real task that reasons across forty steps burns turns and tokens in exactly the same shape as a runaway does. Set the cap low enough to kill loops quickly and you strangle your good long-running work; set it high enough to let that work finish and the broken tool burns all weekend under the same roof. One number can’t separate working hard from stuck — which is the whole reason a flat per-key or per-run budget is a floor, not the answer.
The signal isn’t the token count — it’s the repeat
The sharpest reply in the thread points straight at the real signal: hash the tool-call signature — the tool name plus its arguments — and when the same call fails the same way N times in a row, trip a breaker on that specific call, not the whole run. It kills the loop after about three attempts without punishing a long legitimate task, because legitimate work doesn’t call the identical failing tool with identical arguments over and over. The repetition is the warning.
A bigger cap is a snooze button, not a brake.
This is the per-run breaker from earlier in this series, one notch finer. That post tripped on an identical call repeating; this is the failure-aware version — trip on an identical call that keeps erroring. Same mechanism, better signal: you’re not counting spend, you’re detecting a stuck state and cutting the one call that’s stuck.
I built exactly this breaker and put it in front of a deliberately broken agent, so you can watch it happen: in the live demo, the same tool call fails three times, the breaker hashes the signature, and it cuts that run — while a legitimate 40-step task running right next to it finishes untouched. Same code, open source.
Why a token budget loses the race
There’s a specific reason the token ceiling is the wrong first line of defense here, and it’s about compounding. As another commenter laid it out: an agent’s cost isn’t turns plus output, it’s turns times output — because each turn’s output becomes the next turn’s input. The transcript feeds itself. So the burn is superlinear, and by the time a monthly (or even daily) budget notices, you’ve already paid the fat part of the tail. A ceiling that only warns is measure-then-hope. What actually saves you is a cap that aborts — measure-then-ceiling.
The same thread flagged the invisible line item feeding all of this: every request carries your full tool-schema JSON — a couple hundred tokens per tool — whether the model calls a tool or not. On a loop, that flat tax rides every single turn. Caching the static prefix makes it nearly free — but only if the loop isn’t there to multiply it forty times first. Cap the loop, then shrink the per-turn cost.
Everyone was asking for the same missing thing
Read the thread and one detail stands out: the original poster asks, three separate times, whether there’s a gateway that does this “semantic circuit-breaking out of the box.” Underneath the question, half a dozen tools show up trying to be the answer. That’s the tell — this isn’t an exotic need, it’s a missing default. And it has an address: route every model and tool call through one gateway, and a failure-aware breaker stops being a research project and becomes configuration. Signature hashing, per-run budgets, fan-out caps — they all live at the one door every call already passes through. The uncapped meter never gets capped by watching it more closely; it gets capped by putting a switch in the wire.
If you’re running agents, there’s a broken tool somewhere in your future, and the weekend it picks will be the one you aren’t watching. The fix isn’t a bigger number — it’s a breaker that knows the difference between hard work and a stuck loop, sitting on the request path where it can still act. That’s the gap I close. Every message comes straight to me — I read and reply to each one myself, usually within a business day, and what readers send shapes what I build next. Send me your agent setup and I’ll show you where a loop can still run unbounded — free, within a day.