How to Fix 'agent infinite loop' in LlamaIndex (TypeScript)
When LlamaIndex says agent infinite loop, it usually means the agent kept calling tools or re-planning without ever reaching a final answer. In TypeScript, this often shows up with AgentRunner, ReActAgent, or workflow-based agents when tool outputs don’t give the model a clean path to stop.
Most of the time, the agent is either missing a valid termination condition, returning malformed tool output, or being fed a prompt/tool setup that encourages repeated calls.
The Most Common Cause
The #1 cause is a tool that returns something the agent can’t use to conclude the task, so it keeps calling the same tool again.
A common pattern is using a tool that returns vague text, undefined, or a response that doesn’t clearly satisfy the agent’s instruction.
| Broken pattern | Fixed pattern |
|---|---|
| Tool returns ambiguous output | Tool returns structured, finalizable output |
| Agent prompt doesn’t define stop condition | Agent prompt tells the agent when to answer directly |
| Tool may be called repeatedly with same input | Tool result changes state or clearly resolves query |
// BROKEN: tool output doesn't help the agent terminate
import { FunctionTool, ReActAgent } from "llamaindex";
const lookupCustomer = FunctionTool.from(async ({ customerId }: { customerId: string }) => {
const customer = await db.customers.findById(customerId);
return customer?.name; // too little context
});
const agent = new ReActAgent({
tools: [lookupCustomer],
systemPrompt: "Help the user find customer details.",
});
// This can trigger:
// Error: agent infinite loop
// FIXED: return structured data and define a clear stop condition
import { FunctionTool, ReActAgent } from "llamaindex";
const lookupCustomer = FunctionTool.from(async ({ customerId }: { customerId: string }) => {
const customer = await db.customers.findById(customerId);
if (!customer) {
return JSON.stringify({ found: false });
}
return JSON.stringify({
found: true,
customerId: customer.id,
name: customer.name,
status: customer.status,
});
});
const agent = new ReActAgent({
tools: [lookupCustomer],
systemPrompt:
"Use the tool once. If you have enough information to answer, respond directly and do not call tools again.",
});
If your tool output is just "John" or "done", the model often has no reason to stop. Give it machine-readable output and a prompt that makes termination explicit.
Other Possible Causes
1. Tool always returns the same thing
If a tool is effectively idempotent in a bad way, the agent may keep asking for more because nothing changes.
const getPolicyStatus = FunctionTool.from(async () => {
return "status checked";
});
Fix it by returning actual state:
const getPolicyStatus = FunctionTool.from(async ({ policyId }: { policyId: string }) => {
const policy = await db.policies.findById(policyId);
return JSON.stringify({
policyId,
status: policy?.status ?? "not_found",
updatedAt: policy?.updatedAt ?? null,
});
});
2. Missing or weak maxIterations / step limit
Some agent setups will keep planning until they hit an internal guardrail. If your config doesn’t cap steps, you’ll see loops turn into errors.
const agent = new ReActAgent({
tools: [lookupCustomer],
maxIterations: 20,
});
If your version exposes a different option name, use the equivalent step limit on AgentRunner or your workflow runner. The point is simple: cap runaway reasoning.
3. Tool schema mismatch
If TypeScript types say one thing but runtime input shape says another, the model may keep retrying because every call fails validation.
// BROKEN: expects customer_id but prompt/model sends customerId
const lookupCustomer = FunctionTool.from(
async ({ customer_id }: { customer_id: string }) => {
return JSON.stringify({ customer_id });
}
);
Fix by aligning schema names exactly:
const lookupCustomer = FunctionTool.from(
async ({ customerId }: { customerId: string }) => {
return JSON.stringify({ customerId });
}
);
4. Agent prompt encourages tool spam
If you tell the model to “always verify” or “keep checking,” it may never decide it has enough evidence.
const agent = new ReActAgent({
tools: [lookupCustomer],
systemPrompt:
"Keep using tools until you are absolutely certain and do not answer unless verified multiple times.",
});
That prompt invites loops. Replace it with a bounded instruction:
const agent = new ReActAgent({
tools: [lookupCustomer],
systemPrompt:
"Use tools only when needed. Stop once you have enough information to answer confidently.",
});
How to Debug It
- •
Inspect the last few tool calls
- •Look for repeated calls with identical arguments.
- •If you see
lookupCustomer({ customerId: "123" })five times in a row, your tool output isn’t advancing state.
- •
Log raw tool responses
- •Print exactly what each
FunctionToolreturns. - •Watch for
undefined, empty strings,"ok", or vague text like"checked".
- •Print exactly what each
- •
Check your iteration guardrails
- •Verify
maxIterations, step count, or workflow limits. - •If there’s no cap, add one before chasing deeper bugs.
- •Verify
- •
Validate schema and prompt together
- •Confirm tool argument names match what the model sees in the prompt.
- •Make sure the system prompt includes an explicit stopping rule.
A good debugging log looks like this:
const lookupCustomer = FunctionTool.from(async ({ customerId }: { customerId: string }) => {
const result = await db.customers.findById(customerId);
console.log("lookupCustomer input:", { customerId });
console.log("lookupCustomer output:", result);
return JSON.stringify(result ?? { found: false });
});
If your logs show valid inputs but useless outputs, you’ve found the loop source.
Prevention
- •Return structured JSON from tools instead of short free-text strings.
- •Set an explicit iteration limit on every production agent.
- •Write prompts that say when to stop calling tools and answer directly.
- •Keep tool schemas and TypeScript types aligned; don’t let runtime shapes drift from compile-time assumptions.
If you’re seeing Error: agent infinite loop in LlamaIndex TypeScript, start with the tool output first. In practice, that’s where most loops are born.
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