Timeout and Retry Policies for Long-Running Agents

Setting timeouts and retries right prevents most agent failures in production.

· 11 min read
Cover illustration for “Timeout and Retry Policies for Long-Running Agents”
AI Agent Reliability · September 24, 2026 · 11 min read · 2,442 words

An agent that fails once in a demo is a bug. An agent that fails at 3 a.m. in production, with no clear reason and no clean way to stop it, is an operational incident. Whether someone bothered to bound how long the thing can run, how many times it can retry, and when it hands the problem back to a human separates the two, not model quality or clever prompting. It's whether someone bothered to bound how long the thing can run, how many times it can retry, and when it hands the problem back to a human.

Start with the math, because the math is the whole argument. An agent with an 85% success rate at each step, running eight steps in sequence, doesn't succeed 85% of the time end to end. It succeeds well under a third of the time, since 85% raised to the eighth power falls that far. That's not a rounding error, and it's not a sign that the agent is badly built. It's a structural property of chaining probabilistic steps together, and it means every additional step you add to a task is a tax on reliability, whether or not any individual step is well designed. Bounding task length is, in itself, a reliability decision.

An analysis of 847 AI agent deployments found that 76% failed in production, and 62% of those failures traced back to authentication and state management, not model quality or prompt design. The failure surface, in other words, is mostly operational. And the failures rarely announce themselves. A slow model response, a rate-limited API call, a hallucinated tool invocation, none of these crash the system. They degrade output quietly, long before anything throws an error a monitoring dashboard would flag.

How the MAST taxonomy maps the failure landscape agents inhabit

The most rigorous attempt to catalogue how multi-agent systems actually fail is the MAST taxonomy, built from more than 1,600 annotated traces across seven popular multi-agent frameworks. Its authors ran a careful annotation process on 150 traces with expert human raters, reaching an inter-annotator agreement kappa of 0.88, a level that signals real consensus rather than noisy guesswork. What emerged were 14 distinct failure modes, grouped into three categories: system design issues, inter-agent misalignment, and task verification failures.

The frequency breakdown tells you where to spend engineering effort. Disobeying task specification accounts for 15.7% of failures. Step repetition, agents looping over the same action without making progress, accounts for 13.2%. Reasoning-action mismatch is 12.4%, disobeying role specification is 11.8%, premature termination is 9.1%, task derailment is 8.2%, information withholding is 6.8%, loss of conversation history is 6.2%, and failure to recognize termination conditions is 2.2%.

Two of these numbers matter more than the rest for this article's purposes. Step repetition and unawareness of termination conditions are the failure modes that timeout and retry policy exist specifically to catch. The others matter, but they're context: they explain why agent reliability is a design discipline broadly, not proof that retry logic alone solves the problem. A timeout set too aggressively doesn't fix step repetition; premature termination is 9.1%, a quiet warning against overcorrecting. A timeout set too aggressively doesn't fix step repetition, it just creates a different failure mode.

Zoom out further and the pattern holds. Production failure rates for agent systems without deliberate fault-tolerance design range from 41% to as high as 86.7%, driven by specification problems (41.77%), coordination failures (36.94%), verification gaps (21.30%), and infrastructure issues like rate limits and context overflows (around 16%). None of this is a knock on the underlying models. It's a case for treating reliability as an engineering problem with its own vocabulary and its own tools, separate from the reasoning quality of the agent itself.

Three distinct timeout types and what each one guards against

Most implementations reach for a single timeout and call it done. That's a mistake, because a single timeout can only catch one shape of failure, and agent systems fail in at least three distinct shapes.

The first is the wall-clock, or workflow-level, timeout: a hard deadline on the entire run. If the agent hasn't finished within N seconds, it gets killed. This catches hung processes and infinite waits on external systems, but it's a blunt instrument. A legitimate ten-step task might need several minutes to finish honestly, while a runaway loop could burn through a meaningful chunk of budget in far less time than that. Wall-clock timeout alone can't tell whether the agent is "working slowly" or "spinning uselessly," because both look identical from the outside: elapsed time, no result yet.

The second is the step-level, or start-to-close, timeout, which governs how long a single unit of work, an LLM call, a database write, an external API request, is allowed to run before it's declared failed. Temporal's Python SDK, for example, defaults its start_to_close_timeout parameter to 60 seconds within ModelActivityParameters, and also exposes related controls like schedule_to_close_timeout, schedule_to_start_timeout, heartbeat_timeout, and retry_policy. When pairing LangGraph with Temporal, every node in the graph has to be explicitly designated as either a Temporal Activity, which gets configurable timeouts and retry policy, or a Workflow node, which runs inline and must be deterministic. That designation isn't optional. That designation isn't optional, which forces the question of retry safety to be answered at design time rather than discovered in production.

The third is the heartbeat timeout, and it answers a genuinely different question from the other two. A start-to-close timeout asks "has this call taken too long overall?" A heartbeat timeout asks "is this worker still making progress?" For long-running Activities that are expected to check in periodically, silence beyond the heartbeat interval is the signal that something is stuck. Without it, a worker that's alive but wedged looks identical, from the outside, to one that's grinding through legitimate work.

Diagram: Where Agent Failures Actually Come From. Visualizes: Show the ranked breakdown of the 14 MAST failure modes by frequency, so readers can see at a glance where engineering effort pays off.

Classifying failures before writing a retry rule

Diagram: Classify the Failure Before You Write a Retry Rule. Visualizes: Show the three failure categories — Transient, Permanent, and Ambiguous — as a decision flow, each leading to its prescribed response.

Before deciding how to retry anything, the operative question is simpler and more important: is this failure safe to repeat, or does repeating it make things worse?

Failures split into three categories, and they demand three different responses. Transient failures, connection resets, DNS lookups that fail, timeouts that occur before the request ever left the local infrastructure, 429 responses from a burst of traffic, are safe to retry with backoff, because nothing about the external system's state has changed as a result of the attempt. Permanent failures are the opposite: an HTTP 400 for an invalid request, an HTTP 403 for a permission denial, a rejected VAT number, an item that's out of stock, an approval limit that's been exceeded. None of these change on a second attempt. Retrying doesn't fix a rejected VAT number; it just wastes a call and delays the moment someone finds out the task can't proceed. The correct response is a hard stop and an escalation.

Then there's the category that causes the real damage: ambiguous outcomes. A timeout that occurs after the request body has already been sent means the external system might have received and processed the request just fine, with only the response lost in transit. Retrying blindly here risks a duplicate order, a duplicate charge, a duplicate support ticket, exactly the kind of failure that looks like diligence and is actually recklessness.

The fix is to classify timeouts by where in the request lifecycle they occurred. A timeout before transmission is safe to treat as transient. A timeout after the request body was sent should be treated as unknown, and the workflow's next move should be to query the destination system for the actual status of that request before attempting anything further. That's a materially different design than "catch exception, retry," and it requires the tool integration to expose a status-check path.

None of this classification works without structured error data captured at the point of failure. Every tool integration should log an error category, the HTTP or provider status code, a retry-after value where the provider supplies one, a request identifier, an idempotency key, the attempt number, and a flag for whether the external system may have already changed state. Without that data, classification is a guess dressed up as a policy.

Mechanics of retry policy design: backoff, jitter, counts, and cost-aware budgets

Once a failure is classified as safely retryable, the mechanics of the retry itself matter. The baseline approach is exponential backoff with jitter: a short pause after the first failure, growing exponentially with each subsequent one, with randomization layered in so that many clients failing at once don't all retry in lockstep and create a second wave of load on an already struggling system. Exponential backoff with jitter is estimated to cut retry storms by 60 to 80 percent compared to approaches without jitter. AWS's SDK formula is a reasonable reference point: delay equals a random value between 0 and 1, multiplied by the smaller of 20,000 milliseconds or the base delay times 2 raised to the retry count.

Retry counts should vary by context, not sit at one number applied everywhere. Three to five retries is the standard range for API calls generally. Synchronous, user-facing requests should cap out around three attempts with a total timeout ceiling of 30 seconds, since a user waiting on a screen has a much lower tolerance for delay than a background job does. Background processing can afford five to seven attempts with backoff maxing out around 60 seconds. The Finance Agent Benchmark allows up to eight retry attempts with exponential backoff and randomized jitter specifically for rate-limit errors, and multi-agent negotiation research (arXiv 2605.01750) documents up to ten retries with a base delay of 2 seconds and a cap of 120 seconds for rate-limit errors, alongside a separate cap of three retries for malformed JSON responses and a 1-second cooldown enforced between consecutive API calls.

When a provider sends a Retry-After header, use it instead of a calculated backoff value. The provider knows its own recovery timeline better than the client ever will, and retrying before that window closes just earns another 429 and burns another attempt for nothing.

The gap most implementations miss sits between the step level and the workflow level. Setting a retry count of three per step sounds conservative, until you notice that in an eight-step workflow, each step can independently exhaust its own retry budget. The worst-case number of calls multiplies out fast, and nothing in a per-step retry count catches that. A workflow-level, or session-level, retry budget solves this by tracking total retries, or total spend, across the entire run rather than resetting the counter at every step boundary. A starting default for multi-hop workflows is a step limit around 25, generous enough to accommodate a legitimately long multi-step task, tight enough that a loop gets caught before it turns into a runaway bill.

The danger of retrying when a tool has side effects

Retry safety depends entirely on what the tool actually does when it's called. Retrying a failed read against a vector database or a catalogue lookup carries almost no risk, since a read that fails and succeeds on the second try leaves no trace of the failed attempt. Retrying a payment capture after a timeout is a different animal. The payment provider may have completed the charge on the first attempt and simply failed to return a response in time, and a retry in that situation doesn't recover from an error, it creates a second charge. The same risk applies to order creation, email dispatch, customer notifications, stock reservations, and booking cancellations, any action that changes state somewhere outside the agent's own reasoning loop.

Idempotency is what makes retries safe. A tool built as "create this record if it doesn't already exist" tolerates a retry without incident. A tool built as a blind "create this record" does not, because a retry looks, to that tool, exactly like a second legitimate request. Temporal's documentation is explicit that Activities execute with at-least-once semantics, and recommends designing Activities to be idempotent as a baseline assumption rather than an edge case, typically by deriving an idempotency key from the workflow run ID combined with the activity ID, which downstream services can use to deduplicate. Where a downstream service doesn't honor an idempotency key, the workaround is to store the operation key and its accepted result in an application database, or to design the Activity itself so a retry structurally cannot produce a second irreversible effect.

Multi-step workflows raise the stakes further, because a failure partway through a sequence often means earlier steps have already produced real side effects that a later failure can't simply erase. This is where the Saga, or compensation, pattern comes in: instead of an automatic undo, compensation is treated as a formal business process, with its own approvals and its own audit trail. Compensating actions run in reverse order of the original steps, walking the system back toward a consistent state one step at a time. That's a meaningfully different thing from an "undo" button. Financial, legal, or customer-facing consequences often mean a compensation action needs a human signature before it executes, rather than an automatic reversal triggered by the system that caused the problem.

And some failures simply can't be compensated for by retrying, because they were never transient to begin with. An agent can't argue its way past a rejected VAT number, conjure stock that isn't there, or retry around an approval limit. Those are hard stops, and treating them as anything else is a design error.

Detecting reasoning loops that infrastructure-level monitors cannot see

The most dangerous version of a retry loop is the one that happens inside the model's own reasoning. It's the one that happens inside the model's own reasoning. An agent calls a tool, hits a timeout or an error, and instead of literally retrying the same call, it re-plans: it concludes the previous approach was wrong, and it tries something that looks different, different parameters, a different phrasing of the same request, but the underlying cause is the same rate-limited or unavailable endpoint, which produces a new attempt with the same failure baked in.

This matters because circuit breakers and rate-limit monitors are built to catch repeated identical calls. A reasoning loop doesn't produce identical calls. It produces a sequence of superficially distinct attempts that share the same root cause and the same doomed destination. The infrastructure-level safeguard never fires, because from its vantage point, nothing repeated. The loop is invisible at the layer where most timeout and retry tooling lives, and catching it requires watching the agent's own decision trace, not just the calls it makes, for the pattern of "different words, same wall."

Sources

  1. temporal.io
  2. arxiv.org
  3. fast.io

More in AI Agent Reliability