Applied AI
LangGraph retry limits can reset after an interrupt
Prevent a failing human-in-the-loop node from asking for approval indefinitely across resumes.
October 31, 2026
An approval workflow needs a stopping rule. A LangGraph issue shows a node that calls interrupt() for an amount, resumes, then raises because a service is unavailable. With RetryPolicy(max_attempts=2), the reporter expected the second failure to reach the caller. Instead, each retry asks again and each resume restarts the attempt count; their fixture stops after eight answers without reaching the limit. The issue is open and the behavior should be reproduced in the version a team deploys.
Distinguish prompts from attempts
The LangGraph interrupt guide explains that an interrupted node resumes using a checkpointer and thread ID. For a workflow owner, the important sequence is approval prompt, submitted response, service call, failure, and retry. Log each step with the same business request ID. A user seeing the same question again may assume the first answer was lost or rejected, even when the actual failure is downstream.
Add an external limit
Track attempts for the business operation outside a node-local retry counter if repeated human requests would be costly or confusing. Before presenting another prompt, check a durable operation-level limit and the status of the last service call. Do not automatically repeat an approval for a side effect until you know whether the prior call committed. A failed response can be ambiguous, so idempotency and reconciliation belong beside retries.
Test the failure boundary
In staging, force the service to fail after an interrupt and resume repeatedly. Assert the number of prompts, number of service calls, final error state, and user-visible message. Also test a transient failure that succeeds on retry. A useful fix is one that limits repetition without suppressing a legitimate resume.
Adovo’s view
An approval is a scarce human action. Software should spend it once, then account for what happened. A retry budget that resets at every pause is no budget at all from the customer's seat.
