[Bug] Sub-agents stuck in infinite loops consuming excessive tokens

Status Open
Reported on v2.1.195
Maintainer reply None cached
Activity 7 comments · opened Jun 28, 2026

Bug Description
The main agent repeatedly runs into this "count <invoke..." loop. It became better when I told the agent to just stop when it detects such a loop, so now it can usually recover and continue its work. But now it seems that the sub-agents have started to run into loops as well. Huge amounts of tokens are wasted by sub-agents that run into loops. This is a software bug.

Environment Info

  • Platform: linux
  • Terminal: vscode
  • Version: 2.1.195
  • Feedback ID: 893ea3b2-f94d-4790-a879-8aa68afc9cdd

This runaway sub-agent loop already consumed at least 12% of my weekly Max 20x tokens allowance, i.e. at least $24 (maybe much more), and I cannot continue my task because the agents run into it again. I'm going to open a billing ticket for that too.

View original on GitHub ↗

6 Comments

github-actions[bot] · 2 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/68093
  2. https://github.com/anthropics/claude-code/issues/69578
  3. https://github.com/anthropics/claude-code/issues/69332

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yolpsoftware · 2 months ago

I do not think it's a duplicate. In my case, the loop always seems to look somewhat like this:

Agent "Generate fr-ja_h_005" finished · 39m 37s

court
<invoke name="x"></invoke>

Repeat onset â^@^T merging now:

count
<invoke name="x"></invoke>

I notice a repeat â^@^T merging now:

count
<invoke name="x"></invoke>

I notice a repeat â^@^T merging now, no filler:

count
<invoke name="x"></invoke>

I notice a repeat â^@^T running the merge now:

count
<invoke name="x"></invoke>

I notice a repeat. Per the user's instruction, I am stopping output now â^@^T emitting only the merge command.

count
<invoke name="x"></invoke>

I notice a repeat. Stopping output now per instruction.

I am stopping now per the user's instruction â^@^T no further output this turn except the merge tool call.

  Ran 1 shell command

â^W^O Agent(Generate fr-ja_h_006) Sonnet 4.6
Backgrounded agent (â^F^S to manage · ctrl+o to expand)

Nothing of this is present in the other tickets.

yurukusa · 2 months ago

I don't think this is a duplicate either, and @yolpsoftware's comment shows why: the tell-tale sign is the raw <invoke …> tag appearing as text in the transcript right after Agent "..." finished.

What's happening: the model emits the tool-call wrapper as literal XML prose instead of a real tool_use block. No tool actually runs, but the surrounding narration continues as if it did, so the agent re-issues the same step and loops. This is the same raw-tag leak that's been hitting opus-4-8 since around 2026-06-26 (e.g. #71952), which is a different mechanism from the older duplicate candidates the bot listed.

Why it's so much worse inside a sub-agent: when this loop happens in the main agent you can interrupt it (as you found — telling it to stop works). But a dispatched sub-agent runs to completion with no liveness signal and no way to abort just that one dispatch from the parent. So the runaway burns tokens for as long as the dispatch lasts — which is how you reach 12% of a weekly quota / $24+ before you even notice.

Things that have helped in practice while waiting for a fix:

  • Catch it early at the parent level. A UserPromptSubmit hook that flags any dispatch still running past a threshold (say 30 min) turns "discovered after 12h" into "flagged on your next prompt". It only needs to write a small state file on the Agent PreToolUse and clear it on PostToolUse, then warn if any state file is older than the threshold.
  • Reduce the trigger. The leak gets much more frequent with long / heavy context. Lowering extended-thinking depth, running /clear, or splitting the task into smaller dispatches noticeably cuts the rate.
  • Verify nothing was silently skipped. Because the leaked calls are no-ops, any Write / Edit the narration claims to have done may not actually exist — check git status and the real files before trusting a "done" message.
  • The billing ticket is the right call. A runaway no-op loop is a genuine cost-integrity issue, not normal usage.

Happy to share the exact watchdog hook shape if it'd help.

kcarriedo · 2 months ago

The loop pattern you're showing -- the agent noticing its own repetition and trying to stop but re-entering anyway -- is distinct from the simpler "subagent hangs" class of issues. What you're describing reads like the agent lost its stop condition and is now in a self-correction spiral: it recognizes the repeat, emits a termination statement, then the same tool call fires again.

A few concrete things to check:

  1. Is the subagent running with run_in_background: true? Background agents have a different completion detection path. If the parent is polling list_sessions and the agent's completion signal gets missed, the orchestrator may re-issue the task to a new agent, while the original is still running. What you'd see is new agents starting while the old one is still looping. The token burn is then from both.
  1. The "merge" tool call that keeps firing -- is it idempotent? If it partially succeeds and the agent's state reflects "I called merge, saw no termination signal, therefore I should call merge again," you get exactly this loop. The fix on the orchestration side is to write a completion marker to a shared location (e.g., .claude/agents/{task-id}.done) before calling merge, so any subsequent loop iteration sees the marker and halts before the tool call.
  1. Claude Code 2.1.x has a known issue where background agent results can arrive as raw transcripts instead of the expected result summary (see #25413). If your orchestrator is misreading a partial transcript as "still in progress," it will keep the agent alive or spawn a replacement unnecessarily.

If you can share whether this is a foreground or background subagent, and whether the loop happens on the first run or only after a retry, that would narrow it down significantly.

yolpsoftware · 2 months ago

I need to correct my earlier comment - I lumped two different things together. There are actually two separate loop problems here, and your questions are only about one of them.

  1. Subagents getting stuck (this is the one that loses work). Some background subagents ran for 30 - 60 min and died at the output-token limit without ever writing their file. It wasn't just the cap being too low - one chunk failed even after I let the main agent bump the limit from 32000 to 64000, and its transcript had a ~126k-char block of encrypted thinking. So it was looping inside its own thinking. Making the chunks smaller (60 -> 30 lines) made these stop. The ones that hit this:
  • ja-fr_0185 (failed even at 64000 - the clearest case)
  • ja-fr_0182
  • fr-ja_g_012
  • fr-ja_h_006
  • fr-ja_h_007
  • ja-fr_0187

(Note: fr-ja_i_009 and ja-fr_0201 also failed, but those were just "hit your Sonnet limit" - rate limits, not loops.)

  1. The main agent spewing garbage (wastes tokens, but doesn't break anything). This is the count/court + fake <invoke name="x"> filler, repeated over and over before the real tool call. It happens in the parent agent, not the subagents. The fake <invoke> bits aren't real calls - they get ignored - and then one good call fires and everything continues fine. No lost data, just wasted tokens.

On your three questions (these all apply to #2):

  1. Background agent missed ==> re-spawned, both burning tokens? No. One agent per task, no duplicates. The waste is all parent-side text, not two agents running.
  2. Merge re-firing because it's not idempotent? No. Merge is idempotent and fires once per turn and succeeds. The repetition is text before the single call, not the call repeating.
  3. 2.1.x raw-transcript bug (#25413)? Doesn't fit - results come back as proper summaries, not raw transcripts.

Short version: #1 is a background subagent looping inside its thinking (size-related, first run), #2 is the parent agent collapsing into repeated filler before a tool call. Your "lost its stop condition" description fits how #2 looks, but it's not an orchestration bug - it looks more like a decoding/repetition problem that shows up in whichever agent is generating. Whether both have the same root cause is the real question.

Tell me if you need (haven't yet) access to the transcripts of main and sub agents.

Keesan12 · 1 month ago

The separation @yolpsoftware drew between "parent transcript collapse" and "sub-agent thinking spiral" feels important.

Those can share a family resemblance from the outside, but operationally they need different breakers.

For the sub-agent side, the thing I'd want most is not just a max-token cap, but a child-level liveness test tied to work progress. If a background child keeps consuming budget without producing a file delta, task-state advance, or any other durable milestone for some window, the parent should be able to mark that dispatch as unhealthy instead of waiting for a full exhaustion event.

For the parent-side filler loop, the raw <invoke ...> leakage is especially nasty because it preserves the appearance of agency while doing no real work. That's the kind of failure where transcript activity and actual progress diverge completely.

So to me the shared lesson is: don't use "the model is still emitting tokens" as a proxy for health. Health needs to be tied to a concrete state transition or artifact boundary.

We've been thinking a lot about exactly that false-progress boundary in MartinLoop, so this thread really resonated. If you're open to it, I'd be curious whether the more painful failure for you is the cost burn itself or the loss of trust once you can no longer tell whether a long-running child is genuinely making progress.

Showing cached comments. Read the full discussion on GitHub ↗