Plan and Execute › Handling Failures Gracefully

Michael BrenndoerferJuly 21, 20252 min read
AI Agent HandbookAll chapters
Part 9 of 15Planning - Agents with a Plan
Chapter 25Plan and Execute › Handling Failures Gracefully
Reading section 3 of 10 · Handling Failures Gracefully · 2 minSection 3 of 10 · 2 min

Book contents

Section 3 of 10 · 2 min read

Plan and Execute › Handling Failures GracefullyOne section · Sections in this chapter3 / 10 ↓

Plans rarely execute perfectly. APIs go down, data is missing, or assumptions turn out to be wrong. A robust agent needs to handle these situations without completely falling apart.

Let's say our agent is executing step 2 (checking travel options) and the flight API returns an error. What should happen? The agent has several options:

Option 1: Retry the step. Maybe it was a temporary network issue. Try the same step again, perhaps with a small delay.

Option 2: Use an alternative approach. If the flight API is down, maybe try a train search API instead.

Option 3: Skip and continue. If this step isn't critical, mark it as failed and move on. The user can book their own travel.

Option 4: Re-plan. If the failure makes the rest of the plan impossible, go back to the planning phase and create a new approach.

Here's how we might implement basic error handling:

In[3]:
Code
## Using Claude Sonnet 4.5 for robust error handling in agent workflows
def execute_step_with_retry(step, tools, previous_results, max_retries=2):
    """Execute a single step with retry logic."""
    
    for attempt in range(max_retries + 1):
        try:
            response = client.messages.create(
                model="claude-sonnet-4-5",
                max_tokens=1024,
                tools=tools,
                messages=[{
                    "role": "user",
                    "content": f"Execute: {step}\n\nContext: {previous_results}"
                }]
            )
            
            if response.stop_reason == "tool_use":
                return handle_tool_call(response.content[0])
            else:
                return response.content[0].text
                
        except Exception as e:
            if attempt < max_retries:
                print(f"Step failed (attempt {attempt + 1}), retrying...")
                continue
            else:
                # After all retries, ask agent what to do
                print(f"Step failed after {max_retries + 1} attempts")
                return handle_failure(step, str(e), previous_results)

def handle_failure(failed_step, error, context):
    """Ask the agent to decide how to handle a failure."""
    
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=512,
        messages=[{
            "role": "user",
            "content": f"""This step failed: {failed_step}
            
Error: {error}

Context so far: {context}

What should we do? Options:

1. Try an alternative approach
2. Skip this step and continue
3. Stop and re-plan

Respond with your choice and reasoning."""
        }]
    )
    
    return response.content[0].text

This approach gives the agent some autonomy in handling failures. Instead of hard-coding every possible error scenario, we let the agent reason about what makes sense given the specific situation.