The Tool Call Failed on Step 3. Retry, Skip, or Replan? Decide by What the Failure Told You About the Plan.

A failed tool call carries two facts: the action didn't happen, and something you believed may be false. Agents act on the first and throw away the second — here's the one question that sorts retry from skip from replan, and how to put the answer in the error contract instead of the prompt.

The Tool Call Failed on Step 3. Retry, Skip, or Replan? Decide by What the Failure Told You About the Plan.

A warehouse restocking agent is four steps into a seven-step plan when create_purchase_order returns a 500. The agent retries. Same error. Retries again with a longer timeout. Same error. On attempt five it gives up and reports failure — having burned two minutes and forty tool calls on a supplier whose contract expired last night, which is a fact the error body said on the very first attempt.

The agent had three legitimate responses available. It picked one and never reconsidered. That is the most common structural bug in agent plan execution, and it is not a prompting problem — it is a missing branch in the loop.

The three responses, and what each one quietly assumes

When a step in a multi-step plan fails, an agent can do exactly one of three things, and each is a bet on a different theory of what just happened.

  • Retry bets the failure was transient. The world is fine, your plan is fine, the network hiccuped. Nothing about the remaining six steps has changed.
  • Skip / substitute bets the failure was local. This step is genuinely unavailable, but it was not load-bearing — or another route to the same outcome exists. Steps 5–7 still make sense.
  • Replan bets the failure was informational. The error revealed that a premise the plan was built on is false. Steps 5–7 were derived from that premise and are now garbage.

Most agent loops implement only the first, with a retry counter, and fall through to "report failure" when it runs out. That is a two-state machine pretending to be a three-state one. The skip case gets handled by accident when the model happens to improvise; the replan case gets handled almost never, because by the time the retries are exhausted the agent's context is full of failure noise and it defaults to surrender.

🔍 The question that decides it

Do not classify the failure by its HTTP status. Classify it by this:

Did the error change anything I believed when I wrote the plan?

That single question sorts all three cases cleanly, because it maps onto how the plan was constructed in the first place. A plan is a chain of conditional commitments: because the supplier is active, order from them; because the order exists, notify receiving; because receiving is notified, update the forecast. Every step past the failure inherits the assumptions of the steps before it.

  • Nothing believed has changed → the step is still correct → retry.
  • One belief about this step only has changed → skip or substitute.
  • A belief that later steps depend on has changed → replan from the failure point.

The expired-supplier case is unambiguous under that test. "Supplier contract inactive" invalidates choice of supplier, which steps 5, 6 and 7 all inherit. Retrying is the one response guaranteed to be wrong, and it is the one the agent chose.

Worked example: the same plan, three different errors

Plan: check_stock → select_supplier → create_purchase_order → notify_receiving → update_forecast.

Failure at create_purchase_order, three ways:

Error returned Belief invalidated Correct response
504 upstream timeout none — the PO system is slow retry with backoff
409 duplicate PO for this SKU today "no order exists yet" skip to notify_receiving, referencing the existing PO
422 supplier contract inactive "this supplier can fulfil the order" — inherited by every later step replan from select_supplier

Three responses, one failing tool, one plan. An agent that treats all three as "the tool broke" gets two of the three wrong, and the third only by luck.

⚠️ Note what the 409 case implies: skip is not the same as ignore. The agent skips the action but must carry the discovered fact forward — the later steps need the existing PO's id, not the one that was never created.

Make the error carry the verdict

The reliable fix is not a smarter prompt at the decision point. It is putting the classification in the tool's error contract, where it is code rather than judgment.

class StepFailure(Exception):
    def __init__(self, message, kind, invalidates=None):
        # kind: "transient" | "local" | "premise"
        self.kind = kind
        self.invalidates = invalidates or []   # plan step ids now suspect

raise StepFailure(
    "supplier contract inactive since 2026-09-19",
    kind="premise",
    invalidates=["select_supplier"],
)

The loop then branches without asking the model to intuit anything:

transient -> retry (bounded, with backoff)
local     -> record the discovered fact, continue from the next step
premise   -> discard steps from `invalidates` onward, replan with the error as new context

The model still does the replanning — that part genuinely needs a language model. What it no longer does is decide whether to replan, which is the judgment it is worst at, because that judgment has to be made while staring at an error message that looks superficially like every other error message.

✅ Where a tool cannot know which kind it is throwing (a generic gateway, a third-party SDK), classify at the wrapper: map known error codes to kinds explicitly, and default unknowns to one retry followed by premise. Defaulting to premise is deliberately conservative — an unnecessary replan costs tokens; an unnecessary retry loop costs tokens and ends with a wrong answer.

The tell in your traces

You can find this bug without designing an experiment. Pull any trace where a task failed after more than three calls to the same tool, and read the first error body — not the last. If the first error already contained the information that made the task impossible, the agent was not being resilient. It was refusing to read.

The counterpart tell is quieter and worth grepping for too: a task that succeeded after a step was silently skipped. Check whether the later steps used the substituted fact or the original plan's assumption. A restock that reported success while updating the forecast against a purchase order that was never created is a worse outcome than the honest failure.

The takeaway

Retry is a reflex; it should be a verdict. Every failed step in a plan is two pieces of information — this action did not happen, and something you believed may be false — and agents routinely act on the first while discarding the second. Build the three-way branch into the loop, let the tool layer say which branch applies, and reserve the model's judgment for the one job only it can do: writing the new plan once you have established the old one was built on sand.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.