PMaker home
Classify, then count, then think about circuit breakersRetry on any errorRate limits and bad parameters treated alikeNon-retryable errors exhaust every attemptLayered classificationAPI, tool, context, control flow, one mapping eachOnly the retryable half gets retriedLiveness monitoringA watchdog on streams that are connected but not flowingSilent hangs and broken pairings surfaceThe error-to-policy table is the runtime's first asset

An unclassified failure count is noise — it cannot even answer "should we retry".

Classify Failures Before You Count Them

The first judgment after a failure is not "retry or not" but "is this retryable": four failure layers need four policies, and counts mean something only after classification.

The first judgment after catching a failure is not "should I retry" but "is this worth retrying". A blanket "retry three times on error" treats rate limiting and an illegal parameter as the same thing: the former clears after a few backoff rounds, the latter fails identically however many times you send it — and both end up in the same failure rate. Runtime classification is the precondition for every count and every circuit breaker.

Failures happen in four layers

Layer Typical faces Task-related?
API Rate limit 429, service overload, timeouts, dropped connections, output truncated at the cap No — infrastructure noise
Tool Calling a tool that does not exist, parameters violating the schema, execution exceptions Partly
Context Window overflow, compaction failure, a tool call missing its paired result message Partly
Control flow Loops without progress, death spirals Yes

Sort failures by where they occur, because each layer needs a different response: back off for rate limits, repair pairing for missing results, compact for overflow, break out of loops ai-agent-book-5. What all four share is only the counting. Merge the four layers into one failure-rate curve and you have built a machine for wrong conclusions: tool errors tripling could mean a new model version, or just an upstream service rate limiting — the table cannot tell them apart.

The first call: is it worth retrying

Retryable errors — rate limits, overload, network jitter — become fine on a second pass. Non-retryable ones — illegal parameters, insufficient permissions, a tool that does not exist — retries just burn money; the input or the strategy has to change ai-agent-book-5. Production harnesses keep an error-to-recovery-policy mapping table instead of one vague "retry on error" rule. How to maintain the table: for every error code and exception type, record which layer it belongs to, whether it is retryable, which recovery path handles it, and which counter tracks it. Without this table, no circuit-breaker threshold downstream is meaningful.

Before counting, look for patterns

A single error is easy; the chain-reaction kind is caught by pattern detection. Two signals. Repeated call fingerprints — compute a fingerprint over "tool name + arguments", and the same fingerprint recurring is a hard signal of a no-progress loop. Per-path consecutive-failure counters — every recovery path gets its own counter, which is the next article's breaker threshold ai-agent-book-5. Why structural signals rather than error messages? Distributed fault tolerance splits faults into crash faults and Byzantine faults; agent failures are Byzantine by nature — an agent rarely stops; it keeps producing plausible wrong conclusions, and errors never announce themselves as errors ai-agent-book-10. So classification cannot wait for an exception to appear; it reads fingerprints, counters, and pairing checks.

The worst failure throws nothing

For streaming connections the most dangerous mode is not disconnection — that errors immediately — but the silent hang: the connection is established and the data flow stops, a pipe that is open with no water coming. SDK timeouts often cover only the initial connect, not the transfer, so production agents need an independent idle watchdog: no new output past the threshold means killed and retried. Generalize it: every long-lived connection needs a liveness signal, not just a connection timeout ai-agent-book-5. Trajectory integrity works the same way: when a tool call lacks its paired result, the harness repairs the pairing before injecting into context instead of handing a broken structure to the model or the user. One detail worth copying: some production agents run product mode and training-data collection mode side by side — product mode patches missing messages with placeholders, training mode refuses the patch, because synthetic placeholders poison training data. Same corruption, two policies: the double standard is itself an engineering decision.

Runtime and eval are one pair

The four smoke-failure classes in What to Measure Before You Ship — CAPABILITY, INFRA, TEST_DEFECT, NON_DETERMINISTIC — classify on the evaluation side to decide where effort goes; this article classifies on the runtime side to decide what to do about an error. One spirit, two domains: an unclassified failure number cannot guide any action. The audit is plain: do you have an error-to-policy table? Does every recovery path carry its own counter? Beyond connection timeouts, do long-lived streams have watchdogs? If any answer is no, your retry policy is still superstition.

References

  1. AI Agents in Depth, Chapter 5: Coding Agents and General-Purpose Agents
  2. AI Agents in Depth, Chapter 10: Multi-Agent Collaboration