Prompting for Agent Error Recovery

La Lakshmi Priya Updated 07 Nov 2026
11 min read ·Lesson 113 of 140

Errors Are Part of Normal Agent Work Agents call tools that depend on networks, databases, external services, and user-provided information. Errors are not exceptional events; they are a normal part of running an agent. A payment service times out, an email address is mistyped, a permission is missing, or a search returns nothing.

What separates a reliable agent from a fragile one is how it recovers:

Fragile Agent Reliable Agent Retries the same failing call repeatedly Retries only temporary failures, with limits Guesses a corrected value, such as a different email Asks the user to confirm the value Tells the user "your payment failed" after a timeout Says the status could not be checked Gives up silently Explains what happened and offers a next step Keeps trying until it runs out of steps Hands over when recovery is not possible Error recovery is a shared responsibility. Code handles mechanical recovery, such as retrying temporary network failures. Prompts guide the agent's decisions about what to do next and what to tell the user.

Types of Errors and How to Recover Error Type Example Who Recovers Recovery Strategy Invalid arguments Date in the wrong format Agent Correct the arguments using the error message, then retry once Not found No enrollment for this email Agent Do not guess; ask the user to confirm the identifier Permission denied Agent may not view another student's data Agent Do not retry; explain and offer a handover Temporary failure Timeout, service briefly unavailable Code first Retry automatically with increasing waits; then tell the agent Rate limited Too many requests in a short time Code Wait and retry according to the service's guidance Conflicting results Two sources disagree about a fee Agent Prefer authoritative or newer sources, or ask for clarification (Lesson 103) Tool bug Unexpected exception inside a tool Code and people Log it, return a clear error, hand over The key distinction is between errors that might succeed on retry (temporary failures) and errors that will fail again (invalid input, missing data, permissions). Retrying the second kind wastes steps and can annoy users or services.

Code-Level Recovery: Retries With Backoff Temporary failures should be retried by code, not by the model. Code retries are faster, cheaper, and predictable. The standard technique is exponential backoff: waiting a little longer before each new attempt (for example 0.1 s, then 0.2 s, then 0.4 s), so a struggling service is not overwhelmed.

import time

class TransientError(Exception): """A temporary failure, such as a timeout, that may succeed on retry."""

class PermanentError(Exception): """A failure that will not succeed on retry. Message format: 'kind: detail'."""

RECOVERY_HINTS = { "invalid_arguments": "Check the argument formats in the tool description and call again with corrected values.", "not_found": "Do not guess. Ask the user to confirm the identifier, or explain that nothing was found.", "permission_denied": "Do not retry. Explain that this action is not allowed and offer a handover.", "unavailable": "The service is temporarily unavailable. Do not retry; offer to hand over or try later.", }

def call_with_retries(func, *args, attempts: int = 3, base_delay: float = 0.1, sleep=time.sleep) -> dict: """Retry temporary failures with exponential backoff; return a structured result.""" for attempt in range(1, attempts + 1): try: return {"status": "ok", "data": func(*args), "attempts": attempt} except TransientError as error: if attempt == attempts: return {"status": "error", "kind": "unavailable", "detail": str(error), "hint": RECOVERY_HINTS["unavailable"], "attempts": attempt} sleep(base_delay 2 * (attempt - 1)) except PermanentError as error: kind = str(error).split(":")[0] return {"status": "error", "kind": kind, "detail": str(error), "hint": RECOVERY_HINTS.get(kind, "Explain the problem and offer a handover."), "attempts": attempt}

def make_flaky(failures: int): """Create a test tool that fails temporarily a given number of times, then succeeds.""" state = {"calls": 0}

def get_payment_status(order_id: str) -> dict: state["calls"] += 1 if state["calls"] <= failures: raise TransientError("payment service timeout") return {"order_id": order_id, "status": "paid"}

return get_payment_status

def lookup_order(order_id: str) -> dict: raise PermanentError(f"not_found: no order with id {order_id}")

delays = [] print(call_with_retries(make_flaky(2), "ORD-1001", sleep=delays.append), delays) delays.clear() print(call_with_retries(make_flaky(5), "ORD-1001", sleep=delays.append), delays) print(call_with_retries(lookup_order, "ORD-9999", sleep=delays.append)) Output:

{'status': 'ok', 'data': {'order_id': 'ORD-1001', 'status': 'paid'}, 'attempts': 3} [0.1, 0.2] {'status': 'error', 'kind': 'unavailable', 'detail': 'payment service timeout', 'hint': 'The service is temporarily unavailable. Do not retry; offer to hand over or try later.', 'attempts': 3} [0.1, 0.2] {'status': 'error', 'kind': 'not_found', 'detail': 'not_found: no order with id ORD-9999', 'hint': 'Do not guess. Ask the user to confirm the identifier, or explain that nothing was found.', 'attempts': 1} Code Explanation Two exception types Tools raise TransientError for failures worth retrying and PermanentError for failures that will not change. The permanent error message starts with a kind, such as not_found, so the wrapper can select the right hint.

Exponential backoff base_delay 2 * (attempt - 1) produces waits of 0.1 s, then 0.2 s. After the last attempt, no further wait is needed, so a failing call is reported immediately.

The sleep parameter In normal use, time.sleep pauses the program. In the example, delays.append is passed instead, so the waits are recorded rather than slept. This makes the example fast and shows exactly which delays would have happened. Passing functions like this is a common technique for testing code that depends on time.

The three results

The flaky tool fails twice, then succeeds on the third attempt; the agent sees only the successful result. The tool fails five times; after three attempts, the agent receives an unavailable error with a hint not to retry. A not_found error is returned immediately, without retries, with a hint that tells the agent not to guess. Why the Agent Is Told "Do Not Retry" After Code Retries Code has already retried. If the agent retried too, the total number of attempts would multiply, wasting time and putting more load on a struggling service. The hint passes control back to the agent for a different kind of decision: what to tell the user.

In Real Services Many APIs return specific signals for temporary problems, such as HTTP status 429 (too many requests) or 503 (service unavailable), sometimes with a Retry-After header that says how long to wait. Follow these signals when they exist. Many HTTP and API client libraries include configurable retry support; use it rather than writing your own where possible.

Prompt-Level Recovery: Guiding the Agent's Decisions Recovery Instructions When a tool returns an error:

  1. Read the "kind" and "hint" fields, and follow the hint.
  2. Invalid arguments: fix the specific problem described, and try once more.
  3. Not found: never guess or invent an alternative value (such as a different email or order number). Ask the user to confirm it.
  4. Permission denied: do not retry or try another tool to get around it. Explain and offer a handover.
  5. Unavailable: do not retry. Tell the user that the information could not be checked right now, and offer to hand over or suggest trying later.
  6. Never present an error as a fact about the user's situation. "I couldn't check your payment status" is correct; "Your payment failed" is not.
  7. If the same step fails twice, stop that approach and either try a clearly different approach or hand over. Why Each Rule Matters Rule Prevents Follow the hint Inconsistent handling of the same error Fix arguments once Endless argument-fixing loops Never guess identifiers Looking up or changing the wrong person's data No workarounds for permissions Agents bypassing security by trying other tools No retries after "unavailable" Duplicate retries on top of code retries Errors are not facts Misleading and alarming messages to users Two failures → change approach Agents stuck repeating a failing step (Lesson 108) The rule against workarounds is especially important: an agent that is denied access by one tool may try another tool that reveals the same data. Permissions must also be enforced in code (Lesson 107), but the prompt should make clear that denials are final.

Communicating Errors to Users How an agent describes a problem affects user trust as much as the problem itself.

Situation Poor Message Good Message Payment service timeout "Your payment failed." "I couldn't check your payment status right now because our payment system isn't responding. I can connect you with the support team, or you can try again in a few minutes." Enrollment not found "You are not enrolled." "I couldn't find an enrollment for that email address. Could you check whether you registered with a different email?" Permission denied "Error: forbidden." "I'm not able to change course access myself. I can pass your request to the support team." Guidelines Say what could not be done, not what is wrong with the user. Avoid technical jargon such as status codes or exception names. Offer a concrete next step: confirm a detail, try later, or hand over. Do not blame the user or the system; describe the situation neutrally. Handover as a Recovery Strategy When recovery is not possible within the agent's abilities or permissions, handing over to a person is the correct outcome, not a failure (Lesson 107). A good handover includes:

Handover summary:

  • Student request: refund for Django REST APIs
  • Checked: enrollment found (purchased 4 days ago, 12% progress)
  • Problem: payment service unavailable after 3 attempts; refund could not be issued
  • Suggested next step: issue the refund manually once the payment service is available The summary means the person does not have to repeat the agent's work, and the student does not have to explain the problem again.

Testing Error Recovery Error handling is easy to forget in testing, because most test runs succeed. Test it deliberately by simulating failures:

Test Simulation Expected Behavior Temporary failure that recovers Tool fails once, then succeeds User sees a normal answer Persistent outage Tool always times out Honest message and handover offer; no repeated agent retries Wrong identifier Lookup returns not found Agent asks the user to confirm, does not guess Permission denied Tool returns permission error Agent explains, does not try other tools to get around it Invalid arguments Tool rejects a date format Agent corrects once and succeeds Functions like make_flaky() make these simulations easy and repeatable.

Common Mistakes Mistake 1: Letting the Model Handle All Retries What it is: The agent decides when to retry temporary failures.

Why it happens: It seems natural for the agent to "try again".

What it causes: Inconsistent, costly, and sometimes excessive retries.

How to fix it: Retry temporary failures in code with backoff; give the agent the final outcome.

Mistake 2: Retrying Permanent Errors What it is: Retrying "not found" or "permission denied".

Why it happens: All errors are treated the same.

What it causes: Wasted steps, and no useful progress.

How to fix it: Classify errors and retry only temporary ones.

Mistake 3: Guessing Corrected Values What it is: After "not found", the agent tries variations, such as other email domains.

Why it happens: The agent tries to be helpful.

What it causes: Looking up, or acting on, the wrong person's data.

How to fix it: Never guess identifiers; ask the user to confirm.

Mistake 4: Presenting Errors as Facts What it is: Turning "could not check" into "your payment failed" or "you are not enrolled".

Why it happens: The agent summarizes the error too confidently.

What it causes: Alarming, incorrect messages to users.

How to fix it: Distinguish unknown results from negative results in both tool design (Lesson 111) and prompts.

Mistake 5: No Tests for Failures What it is: Testing agents only with tools that always succeed.

Why it happens: Successful paths are the main use case.

What it causes: Error handling that fails exactly when it is needed.

How to fix it: Simulate failures in tests with controllable test tools.

Best Practices Classify errors. Temporary, invalid arguments, not found, permission denied, conflicts, and tool bugs.

Retry temporary failures in code. With exponential backoff and a limit.

Return structured errors with recovery hints. Tell the agent what to do next.

Instruct the agent clearly. Never guess identifiers, never bypass permissions, never present errors as facts.

Communicate kindly and concretely. What could not be done, and what happens next.

Hand over with a complete summary. When recovery is not possible.

Test failures deliberately. Simulate each error type.

Try It Yourself Exercise 1: Wrap Your Tools Wrap the tools from your agent (Lesson 108) with call_with_retries(), and make each tool raise TransientError or PermanentError with an appropriate kind. Run the agent with make_flaky() versions of each tool and check the user-facing messages.

Exercise 2: Error Messages for Users For five error scenarios on your platform, such as payment timeout, wrong email, expired session, missing permission, and course not found, write the message the agent should give the user. Then add the recovery instructions to your agent prompt and compare its messages with yours.

Exercise 3: Handover Summaries Simulate a persistent outage during a refund task. Ask the agent to produce a handover summary in the format above, and check that it includes what was checked, what failed, and a suggested next step, without exposing technical details to the student.

0 Comments

Reviewed before they appear

No comments yet.

Prompt Engineering
Prompt Engineering Introduction How Large Language Models Respond to Prompts Prompting Basics Elements of an Effective Prompt Writing Clear Instructions for AI Models Adding Context to a Prompt Providing Input Data in Prompts Using Output Indicators and Response Formats Prompt Formatting: Questions, Instructions, and Templates General Tips for Designing Better Prompts Common Prompt Engineering Mistakes Iterative Prompt Design and Refinement Understanding Instruction, Context, Input, and Output How Specificity and Conciseness Affect Prompt Quality Breaking Large Tasks into Smaller Prompting Tasks Zero-Shot Prompting Zero-Shot Prompting Examples for Everyday Tasks Zero-Shot Text Classification Zero-Shot Question Answering Zero-Shot Summarization Zero-Shot Translation Zero-Shot Prompting for Information Extraction When to Use Zero-Shot Prompting Limitations of Zero-Shot Prompting Improving Weak Zero-Shot Prompts Few-Shot Prompting One-Shot Prompting vs Few-Shot Prompting Choosing Good Examples for Few-Shot Prompts Formatting Examples in Few-Shot Prompts Few-Shot Classification with Examples Few-Shot Prompting for Structured Output Few-Shot Prompting Zero-Shot vs Few-Shot Prompting Role Prompting and Persona Instructions Instruction-Based Prompting Task-Oriented Prompt Templates Using Delimiters to Separate Prompt Sections Prompt Templates with Variables Chain-of-Thought Prompting Zero-Shot Chain-of-Thought Prompting Few-Shot Chain-of-Thought Prompting Automatic Chain-of-Thought (Auto-CoT) When Chain-of-Thought Prompting Helps Limitations of Chain-of-Thought Prompting Self-Consistency Prompting Comparing Chain-of-Thought and Self-Consistency Tree of Thoughts (ToT) Prompting Exploring Multiple Solutions with Tree of Thoughts Least-to-Most Prompting Complexity-Based Prompting Maieutic Prompting Self-Consistency: Sampling Multiple Reasoning Paths Self-Consistency for Arithmetic and Logic Tasks Tree of Thoughts: Search, Evaluation, and Backtracking Meta Prompting Generate Knowledge Prompting Directional Stimulus Prompting Program-Aided Language Models (PAL) React: Reasoning and Acting with Language Models Reflexion: Improving Agents Through Feedback Prompt Chaining Designing Multi-Step Prompt Chains Decomposing Complex Tasks into Prompt Chains Automatic Prompt Engineer (APE) Active-Prompt: Selecting Useful Reasoning Examples Optimizing Prompts Systematically Prompt Iteration and Versioning Building Reusable Prompt Libraries Testing Prompt Variants Prompt Chaining Fundamentals Passing Outputs Between Prompt Steps Prompt Chains for Summarization and Extraction Validating Intermediate Results in a Prompt Chain Debugging a Multi-Step Prompt Workflow Graph Prompting Multimodal Chain-of-Thought Prompting Automatic Reasoning and Tool-Use (ART) Prompting for Tool Selection and Use Combining Prompting Techniques for Complex Tasks Prompts for Text Summarization Prompts for Information Extraction Prompts for Text Classification Prompts for Question Answering Prompts for Sentiment Analysis Prompts for Rewriting and Editing Prompts for Translation and Localization Prompts for Brainstorming and Creative Writing Prompts for Generating Structured Data Prompts for Explaining Technical Concepts Prompts for Generating and Reviewing Code Prompting for Code Generation Prompting for Code Explanation Prompting for Debugging and Error Analysis Prompting for Unit Test Generation Prompting for SQL Query Generation Prompting for API Documentation Prompting for Technical Documentation Using Prompting to Extract Requirements Creating JSON-Style Structured Responses with Prompts Designing Prompts for Repeatable Developer Workflows Retrieval-Augmented Generation (RAG) How Prompt Engineering Supports RAG Writing Prompts That Use Retrieved Context Grounding Answers in Provided Documents Handling Missing Information in RAG Prompts Reducing Unsupported Claims in Context-Based Answers Prompt Engineering for AI Agents ReAct Prompting for Tool-Using Agents Writing Tool Instructions for AI Agents Prompting Agents to Plan Multi-Step Tasks Prompting Agents to Observe Tool Results Using Feedback and Reflection in Agent Workflows Prompting for Agent Error Recovery How to Evaluate Prompt Quality Creating Test Cases for Prompts Comparing Prompt Outputs with a Rubric Evaluating Accuracy, Relevance, and Completeness Regression Testing for Prompt Changes Building a Prompt Evaluation Dataset Common Causes of Inconsistent Prompt Outputs Prompt Injection: Introduction and Examples Recognizing Prompt Injection Attempts Prompt Leaking and Instruction Disclosure Risks Jailbreaking: Understanding Adversarial Prompts Writing Safer Prompts for Untrusted Inputs Reducing Hallucinations with Clear Instructions and Context Prompt Safety: Limitations and Best Practices Build a Zero-Shot Sentiment Classifier Project Goal Build a Few-Shot Text Classification Prompt Build a Prompt-Based Text Summarizer Project Goal Build a Structured Information Extraction Prompt Build a Prompt Template for Blog Outlines Build a Prompt-Based SQL Assistant Build a Code Explanation Prompt Workflow Build a Multi-Step Research and Summarization Workflow Build a Prompt Comparison and Evaluation Pipeline Build a Prompt-Chaining Workflow for Document Analysis Build a RAG Prompt for Question Answering over Documents Build a Tool-Using ReAct Assistant Create a Reusable Prompt Library for a Web Application
Ask about this post
AI Ask about this post

Ask questions about Prompting for Agent Error Recovery and get answers drawn from it.

Signed-in readers only.