Objective
Break it: kill your wi-fi mid-run
Do this literally. Start a task, disconnect your network for a few seconds, reconnect. Watch what happens.
An unhandled exception here kills the whole agent, mid-task
Without retry logic, a transient network blip or a 429 rate_limit_error raises an exception straight out of messages.create, and your entire process dies — including any partial progress and every dollar of API spend already used getting to that point. The fix isn't complicated: catch the specific transient errors, wait, retry with exponential backoff (wait longer each time), and only give up after a few real attempts.
import time
def call_with_retry(client, **kwargs):
for attempt in range(4):
try:
return client.messages.create(**kwargs)
except anthropic.RateLimitError:
wait = 2 ** attempt # 1s, 2s, 4s, 8s
print(f"Rate limited, waiting {wait}s...")
time.sleep(wait)
raise RuntimeError("Gave up after 4 attempts")
Notice this only catches RateLimitError (and in the lab you'll add APIConnectionError and APITimeoutError too) — not every exception. A genuine AuthenticationError (bad API key) will never succeed no matter how many times you retry it; retrying that just wastes 15 seconds before failing anyway. Retry logic needs to know the difference between "try again, this is transient" and "this will never work, fail now."
Break it: make a tool fail mid-task
Ask the agent to read_file something that doesn't exist, or feed run_python code with a deliberate syntax error. You already made read_file return an error string instead of raising in Lesson 2 — today you extend that instinct everywhere a tool touches the outside world.
run_python executes a snippet with a typo and the subprocess exits non-zero with a Python traceback in stderr. What should run_tool do with that?
A tool failure is not an agent failure — it's information. Feeding the actual error back as a normal tool_result lets the model see what went wrong and often correct it itself on the next iteration (this is one of the more genuinely impressive things to watch an agent do). Silently swallowing the error removes the model's only chance to self-correct; crashing the agent over a single bad tool call is far too fragile for anything beyond a demo.
Break it: give it a task with no clear finish line
Try "keep researching this topic until you're completely satisfied" — deliberately open-ended. This is what your Lesson 3 max_iterations guard is for, but today check that it fails usefully: does it tell the student what it was doing when it hit the cap, or does it just silently stop?
What you're building
Retry-with-backoff wrapping every API call (not just tool calls), every tool execution wrapped so a failure becomes a tool_result instead of a crash, and a max-iterations message that reports what the agent had accomplished so far — turning all three of today's deliberate breakages into handled, non-fatal cases.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers The Problem, The Concept, Build, Check Yourself, Key Terms & Next — plus a hands-on lab, quiz, and project artifact.
Create a free account — the opening phases of 29 of 35 courses are free, no credit card.