Last week I asked readers a question I genuinely hadn't settled: guard + alert, or guard + retry once? The answers — plus one expensive weekend — gave me a rule. It is not "retry once". It is "retry once, only when the retry is different from the attempt that failed."
Where the question came from
The code-fence guard post ended with my uncertainty: when an LLM completion fails validation, do you retry automatically or send it to review? Two readers gave me the two halves of the answer. One said to retry once with the validation error as feedback, then route persistent failures to review. Another (in a different thread) noted that authorization and quota errors should advance without repeating the same request five times.
Both are the same insight: a retry is only worth it when something changes between attempts. Same request, same conditions, same failure — that is not a retry strategy, that is a hope strategy.
The three failure classes
Every LLM failure in my workflows falls into one of three buckets, and each bucket gets a different response:
1. Transient (retry, with backoff). 429s, 5xx, timeouts, connection resets. The model did nothing wrong; the infrastructure hiccuped. Retry with exponential backoff. This is the only class where an identical retry is legitimate — because the failure was about the moment, not the content.
2. Repairable (retry once, with feedback). The completion came back but failed validation: bad JSON shape, missing required field, wrong enum value. Here the retry must carry the validation error back into the prompt — "your last output failed because action_items was null; return an array" — and it gets exactly one shot. In my experience, the first retry with feedback fixes ~70% of these; the second retry fixes almost none. The failure curve flattens after one.
3. Deterministic (no retry, alert immediately). Auth errors, quota exhaustion, 400s from malformed requests, content-policy refusals, and — the one people miss — a repeated failure of class 2. If the feedback-retry fails the same way, the problem is not in the completion. It is in the prompt, the fixture, or the model. Retrying again burns money to re-confirm a diagnosis you already have. This goes straight to the review queue, tagged for the weekly tally.
The budget in code
The whole policy fits in one n8n pattern. A Code node tracks attempts and classifies the error:
const err = $input.first().json;
const attempts = ($('Classify').first().json.attempts || 0) + 1;
const TRANSIENT = [429, 500, 502, 503, 504, 'ETIMEDOUT', 'ECONNRESET'];
const DETERMINISTIC = [400, 401, 403, 404, 422];
let action = 'review'; // default: a human looks at it
if (TRANSIENT.includes(err.status)) action = attempts <= 3 ? 'retry_backoff' : 'review';
else if (err.validation_failed && attempts === 1) action = 'retry_with_feedback';
else if (DETERMINISTIC.includes(err.status)) action = 'review';
return [{ json: { ...err, attempts, action } }];
Three branches, three budgets: transient gets 3 with backoff, repairable gets exactly 1 with feedback, deterministic gets 0. The action field drives an IF node: retry, or review queue.
The important line is the default. Anything unclassified lands in review, not in a retry loop. A new failure mode you have never seen should never be retried automatically — you do not know its class yet, and an unknown class is a candidate for a new rule, not a guess.
Why exactly one feedback-retry
Two reasons, one empirical and one economic.
Empirical: I logged 200 repairable failures over a month. First feedback-retry success rate: 71%. Second retry on the remaining 29%: 9% of those. The second retry converts at roughly a tenth of the first, and each costs a full prompt+completion. Diminishing returns hit a wall at one.
Economic: retries multiply the cost of the failure path. A workflow that retries three times on every bad completion does not just cost 3x — it costs 3x on precisely the inputs that are hardest to get right. The retry budget is a cost control as much as a reliability control. My weekly tally has a line for retry spend; when it grows, the fix is in the prompt or the fixture, not in the retry count.
The rule that ties it together
Retry only when the attempt differs from the one that failed. Backoff differs. Feedback differs. Same request, same prompt, same conditions — that is not a retry, it is a loop.
When a deterministic failure hits the review queue twice for the same prompt, the weekly tally rule fires: two weeks of the same tag is a model problem, one week is weather (from the model-change protocol post). The retry budget feeds the tally, the tally feeds the protocol. Each mechanism I have posted about — the guard, the crash boundary, the sweeper, the retry budget — is one page of the same SOP.
What is your retry budget? I would especially like to hear from anyone running LLM steps at real volume — where does the second retry ever pay for itself?
Top comments (2)
The rule holds for completions and inverts the moment a step has an effect outside your process, which is worth flagging because an n8n workflow usually contains both kinds of node.
For anything that moves money, a retry has to be byte-identical and carry an idempotency key, and the retry that is different is the dangerous one. A changed request is a second instruction, and the receiving side has no way to know it was meant as a repair. So your class 1 is where the real hazard sits, not class 3. A 504 on a payment initiation does not tell you whether it happened. The caller cannot separate "never arrived" from "arrived and the response was lost", and those two need opposite actions. The fix is not on the caller's side at all: the server has to collapse the duplicate, which puts the decision with whoever holds the key, and leaves the caller with one job, which is not varying the request.
Which suggests the axis is not whether something changed between attempts. It is whether the attempt leaves something behind you cannot take back. Your class 2 is safe to retry with feedback precisely because a failed completion left nothing. The node that posts that completion somewhere is a different rule, and the 70% does not transfer to it.
That 70% then almost nothing on the second is the most useful number in the post, and it matches what I see in validation repair loops. One shot carries nearly all of the recovery, and the second attempt mostly buys you a more expensive copy of the same diagnosis.
That's a sharper axis than the one I used — "does this attempt leave something behind I can't take back" is the cleaner test. I sliced by failure class; you're slicing by reversibility, and reversibility is the one that actually decides the policy.
On the money-moving point, fully agreed: byte-identical retry with an idempotency key, or it isn't a retry at all. The way I operationalize your axis in practice: I tag nodes as pure (the completion goes nowhere but the next node) vs effectful (posts, sends, charges). Pure nodes get the full three-bucket policy including the feedback retry. Effectful nodes get one byte-identical retry only if they carry an idempotency key; no key means zero retries, straight to the review queue. Your observation that class 1 is the real hazard is exactly why — against an effectful node, a changed request isn't a repair, it's a second instruction the server can't distinguish from intent, and a 504 leaves the caller genuinely unable to separate "never arrived" from "arrived, response lost."
Good to hear the 70%-then-nothing curve matches your validation repair loops. That curve flattening after one, across quite different setups, is the most reassuring kind of replication.