The best way in LangGraph to control flow after retries exhausted

What’s the best to control the flow of the graph when a retriable node exhausts all the retries.

We can apply Retry policies to nodes in langgraph like so -
builder.add_node( “node_name”, node_function, retry_policy=RetryPolicy(), )

Now, if I want to redirect the flow to another node when all retries are exhausted (instead of raising that error), I would not use the above retry_policy parameter. Instead I would create my own retry wrapper, wrap it around my method I am trying to execute and call that method in my langgraph node. Inside the langgraph node I handle the retry exhausted error.

Is there a simpler pattern available in LangGraph’s Graph API to help me do this?

I don’t think LangGraph provide a simpler or declarative pattern in the Graph API to automatically redirect flow on retry exhaustion, your approach looks good based on the existent resources.

1 Like

Hi @utkarsh1205

IMHO, what do you think about these examples?

Control flow when retries are exhausted in LangGraph

Short answer: RetryPolicy has no built‑in “on exhaustion, go to X” hook. When a node still fails after all retries, it raises. To redirect flow instead of raising, handle it inside your node and return a Command with goto (or set a flag and route via a conditional edge).

References: Graph API – Retry policies, Command, Conditional edges.

Option 1 (recommended): Manual retry in node + Command.goto fallback

from time import sleep
from langgraph.types import Command

MAX_ATTEMPTS = 3

def work(state):
    for i in range(MAX_ATTEMPTS):
        try:
            data = call_external_api()
            return {"data": data}
        except TransientError as e:
            if i < MAX_ATTEMPTS - 1:
                sleep(2 ** i)  # backoff
            else:
                # retries exhausted -> hop to fallback node
                return Command(update={"error": str(e)}, goto="fallback")

def fallback(state):
    ...

# builder wiring
# builder.add_node("work", work)
# builder.add_node("fallback", fallback)
# builder.add_edge(START, "work")
# builder.add_edge("fallback", END)

This keeps failure local, updates state, and explicitly routes to fallback without throwing.

Option 2: Catch, set a flag, then use conditional edges

def work(state):
    try:
        return {"data": call_external_api(), "failed": False}
    except Exception as e:
        return {"failed": True, "error": str(e)}

def route(state) -> str:
    return "fallback" if state.get("failed") else "next"

# builder.add_node("work", work)
# builder.add_node("next", next_node)
# builder.add_node("fallback", fallback)
# builder.add_edge(START, "work")
# builder.add_conditional_edges("work", route)

Can I keep retry_policy and still redirect?

You can use retry_policy for transient failures, but once it exhausts it raises. There’s no on‑exhaust callback. If you need redirect-on-exhaustion, implement the retry loop inside the node and return Command.goto (Option 1) or use a conditional edge (Option 2).

Functional API note

With @task(retry_policy=...), exhaustion also raises. Redirect by catching in your @entrypoint or by doing manual retries inside the task and returning a value that drives subsequent control flow.