0Pricing
AI Agents · Lesson

Detecting and Recovering from Tool Errors

When a tool 500s, return the error to the model so it can try a different approach instead of crashing.

Detecting and Recovering from Tool Errors is a free AI Agents 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 Agents learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Tools Fail. Plan For It.

Every real tool fails sometimes:

  • Network timeouts
  • Rate limits
  • Bad arguments from the model
  • External service downtime
  • Invalid auth

Production agents must recover gracefully.

Always Return, Never Raise

Inside the agent loop, catch all tool errors and return them as content. Never let an exception kill the loop:

def safe_dispatch(tool_call):
    try:
        args = json.loads(tool_call.function.arguments)
        return TOOLS[tool_call.function.name](**args)
    except json.JSONDecodeError:
        return {'error': 'Arguments are not valid JSON.'}
    except KeyError:
        return {'error': f'Unknown tool: {tool_call.function.name}'}
    except Exception as e:
        return {'error': f'{type(e).__name__}: {e}'}

Structured Error Format

Use a consistent shape so the model recognises errors:

error = {'ok': False, 'error_type': 'TimeoutError', 'error_message': 'Tavily timed out after 10s', 'retryable': True}
print(error)

Distinguish Retryable from Permanent

Some errors warrant a retry (timeout); others do not (404). Tell the model:

if isinstance(e, requests.Timeout):
    return {'ok': False, 'retryable': True, 'error': str(e)}
if isinstance(e, ValueError):
    return {'ok': False, 'retryable': False, 'error': str(e)}

Auto-Retry Transient Errors

For network calls, retry with exponential backoff:

from tenacity import retry, wait_exponential, stop_after_attempt, retry_if_exception_type

@retry(
    wait=wait_exponential(multiplier=1, max=10),
    stop=stop_after_attempt(3),
    retry=retry_if_exception_type((requests.Timeout, requests.ConnectionError))
)
def web_search(query):
    return requests.get('https://api.tavily.com/search', ...).json()

Argument Validation

Before calling the tool, validate arguments with a Pydantic model:

from pydantic import BaseModel, ValidationError

class SearchArgs(BaseModel):
    query: str
    k: int = 5

try:
    args = SearchArgs.model_validate_json(tool_call.function.arguments)
except ValidationError as e:
    return {'error': f'Bad arguments: {e}'}

Show the Model the Error

Append the error as a tool result and call the model again. The model often corrects itself:

messages.append({
    'role': 'tool',
    'tool_call_id': tc.id,
    'content': json.dumps({'error': 'Argument k must be an integer'})
})
# Next model call: 'Sorry, let me retry with k=5...'

Avoid Infinite Error Loops

Some models, when shown an error, retry the same broken call. Cap the loop and detect repeats:

recent_calls = []
for tc in msg.tool_calls:
    key = (tc.function.name, tc.function.arguments)
    if recent_calls.count(key) >= 3:
        return 'Agent stuck in retry loop, aborting.'
    recent_calls.append(key)

Tool-Specific Recovery

For known-flaky tools, build retry logic INSIDE the tool, not the loop:

def search_with_fallback(query):
    try:
        return tavily_search(query)
    except Exception:
        return bing_search(query)   # secondary provider

Timeout Every Call

Every external call needs a timeout. Otherwise one slow service freezes your whole agent:

import requests
response = requests.get(url, timeout=10)  # 10s

# For LLM calls:
from openai import OpenAI
client = OpenAI(timeout=30.0)

Circuit Breakers

When a tool fails repeatedly, "open" the circuit and skip it for some time:

import time

class CircuitOpen(Exception):
    pass

def circuit(failure_threshold=5, recovery_timeout=60):
    def decorator(func):
        state = {'failures': 0, 'open_until': 0}
        def wrapper(*args, **kwargs):
            if time.time() < state['open_until']:
                raise CircuitOpen('circuit is open')
            try:
                result = func(*args, **kwargs)
                state['failures'] = 0
                return result
            except Exception:
                state['failures'] += 1
                if state['failures'] >= failure_threshold:
                    state['open_until'] = time.time() + recovery_timeout
                raise
        return wrapper
    return decorator

@circuit(failure_threshold=3, recovery_timeout=1)
def fragile_tool(x):
    if x < 0:
        raise ValueError('bad input')
    return x * 2

for x in [1, -1, -1, -1, -1]:
    try:
        print('ok', fragile_tool(x))
    except CircuitOpen as e:
        print('blocked:', e)
    except ValueError as e:
        print('failed:', e)

Logging Errors With Context

Log enough to debug after the fact: tool name, arguments, error type, stack trace, request id, user id, trace id. Send to your observability tool.

Graceful Degradation

When a critical tool is down, tell the user honestly instead of pretending the agent succeeded:

if all_search_tools_failed:
    return 'I was unable to search the web right now. Please try again in a few minutes.'

Tool Errors Pattern

What is the safest way to handle tool exceptions inside the agent loop?

Recap

Tools fail. Catch, classify, structure-as-content, and let the agent recover. Add timeouts, retries, and circuit breakers for production reliability.

Frequently asked questions

Is the “Detecting and Recovering from Tool Errors” lesson free?

Yes — the full text of “Detecting and Recovering from Tool Errors” is free to read here on the web, and the AI Agents 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 Agents course, upgrade to CoddyKit PRO.

What will I learn in “Detecting and Recovering from Tool Errors”?

When a tool 500s, return the error to the model so it can try a different approach instead of crashing. You practise AI Agents 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 Agents?

No prior experience is required. AI Agents 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 “Detecting and Recovering from Tool Errors” 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 Agents lesson?

Yes. Every AI Agents 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

  1. ReAct: Reason + Act Pattern
  2. Implementing ReAct from Scratch
  3. Common Tool Sets (Web, Calculator, RAG)
  4. Detecting and Recovering from Tool Errors
← Back to AI Agents