How to Fix 'agent infinite loop during development' in AutoGen (TypeScript)
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.
| Broken | Fixed |
|---|---|
| No termination condition | Explicit stop when done |
| Repeats the same tool call | Stops on final answer |
| Keeps returning non-terminal messages | Returns 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
- •
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, }); - •
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. - •
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
- •
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
maxTurnsor 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
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
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