# ClaudeAgent and CodexAgent retry failed runs on the same session

> Set `retries` on an Agno `ClaudeAgent` or `CodexAgent` and a failed run tries again with backoff. Limits and permanent errors such as authentication or billing fail at once.

- Published: 2026-10-12
- Author: Kaustubh Shukla
- Categories: Changelog
- Canonical: https://www.agno.com/blog/claudeagent-and-codexagent-retry-failed-runs-on-the-same-session
- Markdown: https://www.agno.com/blog/claudeagent-and-codexagent-retry-failed-runs-on-the-same-session.md

Agno's `ClaudeAgent` and `CodexAgent` now take `retries`, `delay_between_retries` and `exponential_backoff` with the same defaults as `Agent`, which are no retries, a one second delay and no backoff. A retry keeps the run id and resumes the Claude SDK session or Codex thread that the failed attempt started, so the model continues the conversation it already had.

Some errors would fail the same way twice, so Agno stops on them. A retry would hand `max_turns`, `max_budget_usd` or a Codex budget or usage limit a fresh allowance, and authentication, billing, bad requests, context window and policy errors don't heal on their own. A cancelled run ends right away, even during the backoff. The durable job queue honours the same verdict and fails the job at once, including after a worker restart.

A streaming client has already received the failed attempt's text when the retry starts. Before each new attempt, the stream yields an `ExternalRunWarningEvent` with `type: "retry"`, so your client can reset the buffered text and keep the tool events. Tool calls from failed attempts stay on the stored run, each one exactly once, and `metadata["attempts"]` counts the attempts.

```python
from agno.agents.base import ExternalRunWarningEvent
from agno.agents.claude import ClaudeAgent

agent = ClaudeAgent(
    id="claude",
    db=db,
    retries=2,
    delay_between_retries=1,
    exponential_backoff=True,
)

for event in agent.run("Run echo alpha", session_id="s1", stream=True, yield_run_output=True):
    if (
        isinstance(event, ExternalRunWarningEvent)
        and event.warning
        and event.warning.get("type") == "retry"
    ):
        print(event.warning["message"], "Delay:", event.warning["delay"])

run = event  # the last item is the RunOutput
print(run.status, (run.metadata or {}).get("attempts", 1))
print([tool.tool_call_id for tool in run.tools])
```

We ran it against the fake Claude SDK from the release's tests, which runs one Bash call and then fails with a 529 on the first two attempts:

```text
Attempt 1 of 3 failed and is being retried; output streamed before this point came from the failed attempt. Delay: 1
Attempt 2 of 3 failed and is being retried; output streamed before this point came from the failed attempt. Delay: 2
RunStatus.completed 3
['call-1', 'call-2']
```

The second and third attempts both resumed SDK session `sdk-1`. A retried attempt can run a tool again, so make tools with side effects outside the workspace safe to repeat before you turn retries on.

See the [cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/frameworks/claude-agent-sdk/claude_retries.py), and learn more about [retries and tool effects](https://docs.agno.com/agent-os/multi-framework/retries) in the documentation.
