Handling Agent Failures and Loops
Add timeout limits, maximum iteration caps, and error-recovery prompts to prevent agents from looping indefinitely or calling broken tools repeatedly.
Handling Agent Failures and Loops is a free AI Engineering Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Engineering Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Agents Fail and Loop
Agents can get stuck in failure loops for several reasons: a broken tool returns an error the agent doesn't know how to escape, the model generates malformed action syntax repeatedly, a task is impossible given the available tools, or the agent keeps calling the same tool with slight variations hoping for a different result. Without safeguards, this burns API budget and never resolves.
Maximum Iteration Limits
The simplest protection is a hard cap on the number of Thought/Action/Observation cycles. LangChain's AgentExecutor accepts a max_iterations parameter. When the limit is hit, the executor stops the loop and returns a message indicating the agent could not complete the task.
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=10, # Hard stop after 10 steps
max_execution_time=30.0, # Also stop after 30 wall-clock seconds
early_stopping_method='generate', # Ask the model for a partial answer at the limit
verbose=True
)Early Stopping: Force a Final Answer
When the agent hits its iteration limit, early_stopping_method='generate' prompts the model one final time with: 'You have reached your step limit. Based on what you know so far, give your best final answer.' This is better than returning a blank response or crashing, as it gives the user something useful.
# The 'generate' early_stopping_method adds this system instruction
# when max_iterations is reached:
#
# 'You have {N} steps remaining but the task is not complete.
# Give your best final answer based on the information gathered so far.'
#
# Contrast with 'force' which abruptly terminates without generating an answer.
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=7,
early_stopping_method='generate'
)Handling Parse Errors Gracefully
When the model produces output that doesn't match the Thought/Action format — missing the action keyword, using the wrong tool name, or outputting free text — the agent raises a OutputParserException. Set handle_parsing_errors=True to feed the error back as an observation so the model can self-correct.
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
handle_parsing_errors=True,
# Custom error message fed back to the model:
# handle_parsing_errors='Please format your response as Thought/Action/Action Input.'
)
# When a parse error occurs, the executor automatically adds:
# Observation: Could not parse LLM output. Please follow the format:
# Thought: ...
# Action: tool_name
# Action Input: ...Detecting and Breaking Repetitive Loops
A common loop pattern: the agent calls search('same query') three times in a row, each time getting the same useless result. Implement loop detection by tracking recent (tool, input) pairs. If the same combination repeats more than twice, inject an observation that suggests a different approach.
from collections import Counter
class LoopDetector:
def __init__(self, max_repeats: int = 2):
self.max_repeats = max_repeats
self.call_counts = Counter()
def check(self, tool_name: str, tool_input: str) -> bool:
key = f'{tool_name}:{tool_input}'
self.call_counts[key] += 1
if self.call_counts[key] > self.max_repeats:
return True # Loop detected
return False
def get_warning(self) -> str:
return ('You have called this tool with the same input multiple times. '
'Try a different approach, different search terms, or a different tool.')Tool-Level Error Handling
Robust agents require robust tools. Every tool should catch its own exceptions and return structured error messages rather than raising Python exceptions. Include the error type and a suggestion for the agent so it knows whether to retry, change its approach, or escalate.
from langchain_core.tools import tool
import requests
@tool
def get_company_data(company_name: str) -> str:
'''Retrieve company information from the business database.
Input: company name as a string.
'''
try:
resp = requests.get(
f'https://api.example.com/companies/{company_name}',
timeout=5
)
if resp.status_code == 404:
return f'No company found with name "{company_name}". Try the exact legal name or ticker symbol.'
if resp.status_code == 429:
return 'Rate limit exceeded. Wait 60 seconds before trying again.'
resp.raise_for_status()
return resp.json().get('summary', 'No summary available.')
except requests.Timeout:
return 'The database is not responding. Try searching the web instead.'Exponential Backoff on API Failures
When tools call external APIs, transient failures are common. Add retry logic with exponential backoff inside the tool function — retry up to 3 times with increasing waits between attempts. This handles rate limits and brief outages transparently without the agent needing to know about retries.
import time
import requests
from langchain_core.tools import tool
@tool
def reliable_search(query: str) -> str:
'''Search with automatic retry on failure. Input: search query string.'''
max_retries = 3
for attempt in range(max_retries):
try:
resp = requests.get(
'https://api.duckduckgo.com/',
params={'q': query, 'format': 'json'},
timeout=10
)
resp.raise_for_status()
data = resp.json()
return data.get('AbstractText', 'No results found.')
except requests.RequestException as e:
if attempt < max_retries - 1:
wait = 2 ** attempt # 1s, 2s, 4s
time.sleep(wait)
else:
return f'Search failed after {max_retries} attempts: {str(e)}'Timeout Budgets at the Agent Level
Individual tool retries are great, but you also need a total wall-clock timeout for the entire agent run. If the task takes longer than your SLA allows (say, 30 seconds), stop the loop and return a graceful degradation response. LangChain's max_execution_time parameter handles this at the executor level.
import asyncio
async def run_with_timeout(user_input: str, timeout_seconds: float = 30.0) -> str:
try:
result = await asyncio.wait_for(
agent_executor.ainvoke({'input': user_input}),
timeout=timeout_seconds
)
return result['output']
except asyncio.TimeoutError:
return ('I am taking longer than expected to answer this question. '
'Please try again with a simpler question, or check back later.')Logging Failures for Analysis
Every agent failure is data. Log the full trace — user input, all intermediate steps, the failure reason, and the number of iterations used — to a database or observability platform. Analysing failure patterns reveals which tools are unreliable, which question types the agent cannot handle, and which loops occur most often.
import logging
import json
logger = logging.getLogger('agent')
def run_and_log(user_input: str) -> str:
try:
result = agent_executor.invoke(
{'input': user_input},
return_intermediate_steps=True
)
if not result.get('output'):
logger.warning('Agent returned empty output', extra={
'input': user_input,
'steps': len(result.get('intermediate_steps', []))
})
return result['output']
except Exception as e:
logger.error('Agent failed with exception', extra={
'input': user_input,
'error': str(e),
'error_type': type(e).__name__
})
return 'I encountered an error. Please try rephrasing your question.'Injecting Recovery Hints Into the Prompt
When you detect a failure pattern, you can dynamically inject recovery instructions into the agent's next prompt. For example, if the search tool has been failing, add a hint like: 'The web search tool is currently unreliable. Prefer the knowledge base tool for this query.' This steers the agent toward a working solution without hard-coded fallback logic.
Testing Failure Scenarios
Build an explicit test suite for failure scenarios. Test what happens when: all tools return errors, the model hits max_iterations, the input contains no answerable question, and the model calls a non-existent tool. Your agent should always return a sensible message and never crash the application, no matter how adversarial the situation.
Quick Check
Test your understanding of handling agent failures and preventing loops.
Lesson Recap
In this lesson you learned: max_iterations and max_execution_time set hard limits on agent runtime, handle_parsing_errors feeds format mistakes back to the model for self-correction, and tools should catch exceptions and return descriptive error strings rather than raising. Next up we explore OpenAI's native function calling feature for structured tool integration.
Frequently asked questions
Is the “Handling Agent Failures and Loops” lesson free?
Yes — the full text of “Handling Agent Failures and Loops” is free to read here on the web, and the AI Engineering Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Engineering Academy course, upgrade to CoddyKit PRO.
What will I learn in “Handling Agent Failures and Loops”?
Add timeout limits, maximum iteration caps, and error-recovery prompts to prevent agents from looping indefinitely or calling broken tools repeatedly. You practise AI Engineering Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start AI Engineering Academy?
No prior experience is required. AI Engineering Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Handling Agent Failures and Loops” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this AI Engineering Academy lesson?
Yes. Every AI Engineering Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The ReAct Framework: Think, Act, Observe
- Defining Tools for Your Agent
- Building a ReAct Agent with LangChain
- Handling Agent Failures and Loops