How to Fix 'agent infinite loop during development' in AutoGen (TypeScript)

By Cyprian AaronsUpdated 2026-04-21
agent-infinite-loop-during-developmentautogentypescript

An agent infinite loop during development error in AutoGen TypeScript usually means your agent graph is bouncing between the same messages, tools, or handoffs without ever reaching a terminal condition. You’ll see it when the model keeps calling the same tool, re-emits the same assistant message, or your termination logic never fires.

In practice, this shows up during local dev when you wire up a AssistantAgent, UserProxyAgent, or a group chat flow and forget to define a real stop condition.

The Most Common Cause

The #1 cause is a missing or ineffective termination check. In AutoGen, if your agent keeps producing responses that look “valid” but never satisfy a stop rule, the runtime keeps iterating until it hits an internal loop guard.

A common broken pattern is using a message handler that always returns another task instead of ending the conversation.

BrokenFixed
No termination conditionExplicit stop when done
Repeats the same tool callStops on final answer
Keeps returning non-terminal messagesReturns null / terminator signal
// Broken pattern
import { AssistantAgent } from "@autogen/agent";

const agent = new AssistantAgent({
  name: "support_agent",
  systemMessage: "Solve the user's issue.",
});

await agent.run({
  task: "Check account status",
  onMessage: async (msg) => {
    // Always triggers another turn
    return {
      role: "user",
      content: "Continue checking account status",
    };
  },
});
// Fixed pattern
import { AssistantAgent } from "@autogen/agent";

const agent = new AssistantAgent({
  name: "support_agent",
  systemMessage: "Solve the user's issue. Stop when you have the answer.",
});

await agent.run({
  task: "Check account status",
  onMessage: async (msg) => {
    if (msg.content?.includes("Final answer")) {
      return null; // terminate conversation
    }

    return {
      role: "user",
      content: "Provide the final answer only if all checks are complete.",
    };
  },
});

If you’re using tool calls, the same problem happens when the model keeps selecting the same function because your tool output doesn’t change state.

Other Possible Causes

1) Tool output does not change state

If your tool returns the same payload every time, the model has no reason to stop.

// Bad: always returns identical result
async function getBalance() {
  return { balance: 1000 };
}

// Better: include state or terminal context
async function getBalance(accountId: string) {
  return { accountId, balance: 1000, fetchedAt: new Date().toISOString() };
}

If you use FunctionTool, make sure repeated calls are not indistinguishable from successful progress.

2) Missing max turns in group chat

With GroupChat / GroupChatManager, leaving turn limits open can create endless back-and-forth between agents.

const groupChat = new GroupChat({
  agents: [planner, executor],
  maxTurns: 20,
});

Without maxTurns, a planner that keeps asking for clarification can bounce forever.

3) Recursive handoff logic

A handoff chain like agentA -> agentB -> agentA is easy to create accidentally in TypeScript if each agent delegates back to the previous one.

// Bad handoff cycle
if (needsReview) return reviewAgent;
if (needsExecution) return executionAgent;
// reviewAgent sends back to plannerAgent again

Break the cycle with an explicit terminal route:

if (needsReview) return reviewAgent;
if (needsExecution) return executionAgent;
return finalizerAgent;

4) Prompt tells the model to “keep going”

This is more common than people admit. If your system prompt says things like “continue until fully resolved” without defining what resolved means, GPT-style agents often overrun.

const agent = new AssistantAgent({
  name: "claims_agent",
  systemMessage:
    "Keep investigating until everything is fully resolved and be thorough.",
});

Use bounded instructions instead:

const agent = new AssistantAgent({
  name: "claims_agent",
  systemMessage:
    "Investigate for at most 3 steps. Stop when you have enough information to answer.",
});

How to Debug It

  1. Print every turn Log role, content, and any tool call name. If you see the same assistant message or tool call repeating, you’ve found the loop source.

    console.log({
      role: msg.role,
      content: msg.content,
      toolCalls: msg.toolCalls,
    });
    
  2. Check termination conditions first Verify whether you’re using maxTurns, stop phrases, or a custom termination callback. In AutoGen TypeScript, missing one of these is usually enough to cause repeated turns.

  3. Inspect tool outputs Look for tools that always return success but never move state forward.

    • Same JSON every time
    • No “done” flag
    • No exception on invalid input
  4. Reduce to two agents Strip your setup down to one assistant and one user proxy. If the loop disappears, your bug is in handoff logic or group chat routing, not in LLM behavior.

Prevention

  • Set explicit termination rules on every multi-turn workflow.
  • Add maxTurns or equivalent guardrails to every chat manager.
  • Make tool outputs stateful and observable:
    • include IDs
    • include timestamps
    • include completion flags

For production systems, I also recommend logging:

  • turn count per session
  • repeated tool names
  • repeated identical assistant messages

If you see those metrics climbing together, you’re not debugging an LLM problem. You’re debugging a control-flow problem in your agent graph.


Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides