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

By Cyprian AaronsUpdated 2026-04-21
agent-infinite-loopautogentypescript

What the error means

agent infinite loop in AutoGen usually means your agents keep producing messages, but nothing in the conversation ever satisfies the termination condition. In TypeScript, this often shows up when you wire an AssistantAgent and UserProxyAgent together, but forget to stop on a final answer, tool result, or max turn limit.

The pattern is simple: the conversation keeps bouncing between agents until AutoGen gives up or your app hangs.

The Most Common Cause

The #1 cause is a missing or broken termination condition. In AutoGen TypeScript, this usually happens when isTerminationMessage never returns true, or your agent always replies even after it has already answered the question.

Here’s the broken pattern:

import { AssistantAgent, UserProxyAgent } from "@autogen/agentchat";

const assistant = new AssistantAgent({
  name: "assistant",
  llmConfig: { model: "gpt-4o-mini" },
});

const user = new UserProxyAgent({
  name: "user",
  humanInputMode: "NEVER",
});

await user.initiateChat(assistant, {
  message: "Summarize this invoice.",
  maxRound: 20,
});

And here’s what is happening:

BrokenFixed
No explicit termination ruleStop when the assistant produces a final answer
maxRound is high enough to hide the bugUse a real stop condition, not just a timeout
Agent keeps responding foreverConversation ends on TERMINATE or equivalent

Fixed version:

import { AssistantAgent, UserProxyAgent } from "@autogen/agentchat";

const assistant = new AssistantAgent({
  name: "assistant",
  llmConfig: { model: "gpt-4o-mini" },
});

const user = new UserProxyAgent({
  name: "user",
  humanInputMode: "NEVER",
  isTerminationMessage: (msg) => {
    return typeof msg.content === "string" && msg.content.includes("TERMINATE");
  },
});

await user.initiateChat(assistant, {
  message: "Summarize this invoice and end with TERMINATE.",
  maxRound: 10,
});

If your agent framework version uses a different hook name, the fix is the same: define one clear exit path and make both sides respect it.

Other Possible Causes

1. Tool calls never resolve

If a tool call throws, returns malformed data, or never resolves, the assistant often retries the same action and looks stuck in a loop.

// Broken
const tools = [{
  name: "lookupPolicy",
  description: "Fetch policy details",
  execute: async () => {
    throw new Error("DB timeout");
  },
}];

Fix it by returning structured failures and teaching the assistant to stop retrying:

// Fixed
const tools = [{
  name: "lookupPolicy",
  description: "Fetch policy details",
  execute: async () => {
    try {
      return { ok: true, data: await fetchPolicy() };
    } catch (err) {
      return { ok: false, error: "DB timeout", retryable: false };
    }
  },
}];

2. The system prompt encourages endless refinement

A prompt like “keep improving until perfect” can make the model keep revising instead of finishing.

// Broken
systemMessage:
  "Review the claim response and keep refining it until it is as good as possible."

Use an explicit completion rule:

// Fixed
systemMessage:
  "Review the claim response once. If it meets requirements, output final answer and end with TERMINATE."

3. Message history is being replayed incorrectly

If you append the same assistant output back into history on every turn, AutoGen will see repeated context and may keep generating similar replies.

// Broken
history.push(lastAssistantMessage);
history.push(lastAssistantMessage); // duplicated by accident

Make sure each turn adds exactly one new message per speaker.

4. Max turns are too high and masking a logic bug

A large maxRound does not fix a loop. It only delays failure.

// Broken
await user.initiateChat(assistant, {
  message: "Process this request.",
  maxRound: 100,
});

Lower it while debugging:

// Fixed
await user.initiateChat(assistant, {
  message: "Process this request.",
  maxRound: 5,
});

If it still loops at five turns, your stop condition is wrong.

How to Debug It

  1. Print every message in the conversation

    • Log role, content, and whether a tool was called.
    • You want to see which message repeats.
  2. Check termination logic first

    • Confirm isTerminationMessage, stop tokens, or final-answer rules are actually reachable.
    • If your assistant never emits TERMINATE, the chat will not end.
  3. Disable tools temporarily

    • Run the same conversation with tools removed.
    • If looping stops, your tool handler is returning bad output or throwing repeatedly.
  4. Reduce maxRound and simplify prompts

    • Set maxRound to something small like 3 or 5.
    • Replace complex prompts with a single instruction:
      • “Answer once and stop.”
    • If that works, add complexity back one piece at a time.

Prevention

  • Always define one explicit termination contract:
    • A token like TERMINATE
    • A final-answer schema field like { done: true }
  • Treat tool outputs as API responses:
    • Return structured success/failure objects
    • Never let exceptions bubble into silent retries
  • Add chat-level tests:
    • One test for normal completion
    • One test for tool failure
    • One test for repeated-agent-message detection

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