THE RETRY CARD · the retry review · what to retry, how long to wait, what never to repeat
WAKES WHEN 429 or 529 errors break a batch or an agent, someone asks which errors to retry, a retry loop is written or reviewed, calls hang past a deadline, or a retry might send or charge twice
THE METHOD
policy retry-policy.json — the policy against the error table, the waits, the worst case, every finding with its fix.
trace error-log.jsonl --policy retry-policy.json — a real night replayed, call by call.
simulate --policy … --scenario … --runs N --seed S — policies compared on the same made-up draws.
table — the error facts and the SDK facts, with their pages and dates.
The team changes the policy and checks it again.
REFUSES
Retry rules from memory
Advising a retry of an error that never clears
Presenting a simulation as a measurement
Ignoring a side effect a retry would repeat
IT MAKES policy — a retry policy against the API's errors; exit 1 on any ERROR; trace — replay an error log, call by call; exit 1 on any ERROR; simulate — the policy against a made-up scenario, seeded; table — the error table and the SDK facts, with sources and dates.
THE LAW The error facts are dated data from the docs, never memory. What never clears is never retried; retry-after is the least wait. A timeout may have run: a side effect is retried only under an idempotency key. The worst case is computed, printed with its formula, and set against the deadline. A simulation is made up; a log is real. The policy is the team's; the card proposes.
IN THE BOX scripts/retry.py · assets/api-rules.json · the formats · the error table and checks · the method by hand · the sources · ten tests.
PROOF selftest 28/28; a nightly batch job's policy (10 ERROR), its night replayed (11 ERROR), the fixed policy, and the trigger test, on the record (WITNESS.md) · witnessed 2026-10-13 · EDITION 1.
THE SEAL 96 of 100 · LEGENDARY · WITNESSED · Trigger 5 · Machinery 5 · Law 5 · Portability 5 · Proof 4
IT CAN BE WRONG an AI reading a text file: it can be wrong and can invent a number, a rule, a name or a date; check what matters against your own records and the source; the risk is yours. LICENSE-NOTE.md rides in the packet and is the licence.
THE PUNCH · SHA-256 OF SKILL.MD · B55BF7A640463BE42F2B8C29
CITE THIS CARDTHE RETRY CARD, Edition 1. Lund Studio LLC, Westminster, Colorado. https://lundr.tech/?view=retry-card. Punch B55BF7A640463BE42F2B8C29. Retrieved 2026-10-13.
What it is.
A review of how an app retries failed Claude API calls, before it ships and after a bad night. Against the API's errors as read from the docs, it finds:
Use it whenever 429 or 529 errors break a batch or an agent, someone asks which errors to retry, a retry loop is written or reviewed, calls hang past a deadline, or a retry might send or charge twice. Not for testing against a stand-in service (THE DRY RUN CARD), Claude Code in CI (THE HEADLESS CARD), repeated work as skills (THE REPEAT CARD), raising rate limits.
It carries a machine that shows its working: policy — a retry policy against the API's errors; exit 1 on any ERROR; trace — replay an error log, call by call; exit 1 on any ERROR; simulate — the policy against a made-up scenario, seeded; table — the error table and the SDK facts, with sources and dates — 28 checks in its selftest.
It answers requests such as “529 overloaded errors keep killing our batch job”, “which Anthropic API errors should we retry?”, “we retry five times with a fixed two-second wait: is that fine for 429s?”, “the SDK retries twice and we wrap it in our own loop: how many requests is one call?”, “if the call times out after the agent sent the email, does a retry send it twice?”.
Six laws, written into the card.
They are in the card itself, so the AI follows them.
THE ERROR FACTS ARE DATED DATA FROM THE DOCSThe error facts are dated data from the docs, never memory.
WHAT NEVER CLEARS IS NEVER RETRIEDWhat never clears is never retried; retry-after is the least wait.
A TIMEOUT MAY HAVE RUNA timeout may have run: a side effect is retried only under an idempotency key.
THE WORST CASE IS COMPUTEDThe worst case is computed, printed with its formula, and set against the deadline.
A SIMULATION IS MADE UPA simulation is made up; a log is real.
THE POLICY IS THE TEAM'SThe policy is the team's; the card proposes.
The method.
policy retry-policy.json — the policy against the error table, the waits, the worst case, every finding with its fix.
trace error-log.jsonl --policy retry-policy.json — a real night replayed, call by call.
simulate --policy … --scenario … --runs N --seed S — policies compared on the same made-up draws.
table — the error facts and the SDK facts, with their pages and dates.
The team changes the policy and checks it again.
What rides in the card.
In the card’s own voice, with a machine that shows its working.
THE REFERENCESreferences/POLICY-FORMAT.md · SOURCES.md · THE-ERRORS.md · THE-METHOD.md
THE MACHINEscripts/retry.py · four commandspolicy — a retry policy against the API's errors; exit 1 on any ERROR; trace — replay an error log, call by call; exit 1 on any ERROR; simulate — the policy against a made-up scenario, seeded; table — the error table and the SDK facts, with sources and dates. 28 checks in its selftest. Needs: Python 3; the retry policy as JSON, and an error log if there is one.
What it does once your AI has it.
policy A retry policy against the API's errors; exit 1 on any ERROR
trace Replay an error log, call by call; exit 1 on any ERROR
simulate The policy against a made-up scenario, seeded
table The error table and the SDK facts, with sources and dates
On the record Example Co's nightly batch: its policy (10 ERROR, 15 requests a call), one night replayed (11 ERROR, an email sent twice), and the fixed policy; 39 of 48 in the trigger test after the rewrite
What it refuses, and where it hands off.
It refuses retry rules from memory; advising a retry of an error that never clears; presenting a simulation as a measurement; ignoring a side effect a retry would repeat.
testing code against a stand-in service that fails on purpose → THE DRY RUN CARD
running Claude Code in CI → THE HEADLESS CARD
turning repeated work into skills → THE REPEAT CARD
raising rate limits → the account's own contact with the platform
The policy as written, not the code that runs it; the error facts were read 2026-10-12 and change; a simulation is not a measurement. It is an AI reading a text file: it can be wrong, so check what matters against your own records and the source.
What’s in the buy.
CARD.md — the whole card: its boot, law, method, machine, seals, refusals and hand-offs, ledger, score and what it carries · SKILL.md — the door your AI reads first · START-HERE.md — the first five minutes, for you
POLICY-FORMAT.md + SOURCES.md + THE-ERRORS.md + THE-METHOD.md — in references/, in the card's own voice
scripts/retry.py — the machine: policy · trace · simulate · table; see NEEDS below; selftest 28/28
WITNESS.md — the run on a realistic case as printed, and the trigger test on Haiku, Sonnet and Opus · SELFTEST.md — the machine's own test, as run at the cut · AUDIT.md, the twelve checks · MANIFEST.md, every file hashed
tests/evals.json — the cases it must take, hand off and refuse
MY-LEDGER.md — the card's memory, on your own machine · TIN.md, the nine lines on the tin · LICENSE-NOTE.md · HOSTS.md, where it runs
system/short-prompt.md and system/system-prompt.md — the doors for any AI without skills
PROOF · SELFTEST 28/28 · WITNESSED ON A RUN · TRIGGER TEST 36 OF 48 ON ITS OWN PROMPTS · HAIKU 4/16 · SONNET 16/16 · OPUS 16/16 · 0 WRONG PICKS · EDITION 1 · PUNCH B55BF7A640463BE42F2B8C29
ON EVERY DOOR · A CARD FOR YOUR AI, A FILE FOR YOUR COMPUTER
In Claude: turn on code execution under Settings › Capabilities, then Customize › Skills › + › Create skill, and upload the zip as it is — START-HERE.md in the box walks you through it, and tells you how to keep the ledger. In ChatGPT, Gemini and the rest: a Project, a GPT or a Gem with the card’s files attached and the short door in the box pasted as its instructions. The words run anywhere an AI reads Markdown; the machines run wherever the host runs Python. Witnessed in Claude only. The host marks →
Take it.
Nº 968 — LAUNCHING SOON
Sold as is under the term printed. A card instructs an AI you operate; results depend on your model, your files and your judgement. Not medical, legal, tax or financial advice, never the person’s boss, and not a licence to practise. The terms →
One payment. The file is yours to keep and keeps working at its edition; new editions issued in the year after you buy reach you by email as replacement files. Tax is added at checkout where it applies. Nothing auto-renews.
A TERM, NOT A SUBSCRIPTION: NOTHING RENEWS ITSELF AND NOBODY IS CHARGED AGAIN. WHEN A TERM ENDS THE FILES STAY ON YOUR COMPUTER AND STAY READABLE — FREEZE, NOT LOSS.
THE MACHINE · IN THE OPEN · FROM THE CARD’S OWN WITNESS.MD AND SELFTEST.MD
retry.py, every command showing its working.
A small Python program. Your AI runs it; you can too. The blocks below are pasted from the card’s own record, as printed.
policy
a retry policy against the API's errors; exit 1 on any ERROR
trace
replay an error log, call by call; exit 1 on any ERROR
simulate
the policy against a made-up scenario, seeded
table
the error table and the SDK facts, with sources and dates
selftest
28 checks that prove the machine; it must print 28/28
python3 scripts/retry.py policy team-policy.json
RETRY POLICY CHECK · team-policy.json · rules as read 2026-10-12
WHAT IT RETRIES, AGAINST THE API'S ERRORS
status type the docs say this policy
400 invalid_request_error NEVER retries ← wrong
401 authentication_error NEVER retries ← wrong
402 billing_error NEVER retries ← wrong
403 permission_error NEVER retries ← wrong
404 not_found_error NEVER retries ← wrong
409 conflict_error AFTER FIX retries
413 request_too_large NEVER retries ← wrong
429 rate_limit_error RETRY AFTER retries
429 spend cap rate_limit_error NEVER retries ← wrong
500 api_error RETRY retries
504 timeout_error RETRY retries
529 overloaded_error RETRY retries
stream overloaded_error RETRY (not streaming)
connection - RETRY · AMBIGUOUS retries
timeout - RETRY · AMBIGUOUS retries
408 - RETRY retries
5xx - RETRY retries
FINDINGS
ERROR P1 retries 400 invalid_request_error: the format or content of the request is wrong, or a spend limit you set was reached: it fails the same way until that changes
fix: add it to never_retry
ERROR P1 retries 401 authentication_error: the key is malformed, revoked or expired
fix: add it to never_retry
ERROR P1 retries 402 billing_error: billing or payment details need attention
fix: add it to never_retry
ERROR P1 retries 403 permission_error: the key may not use this resource
fix: add it to never_retry
ERROR P1 retries 404 not_found_error: the path or a resource id does not exist
fix: add it to never_retry
ERROR P1 retries 413 request_too_large: over the maximum request size (Messages 32 MB, Batch 256 MB): shrink the request
fix: add it to never_retry
ERROR P1 retries 429 (the spend cap): the tier's monthly spend cap: no retry-after header, and every retry (the SDK's included) fails until access resumes
fix: set spend_cap_stop: true
ERROR P4 retries 429 without honouring retry-after: the docs say retry-after gives the seconds to wait and earlier retries will fail
fix: set honor_retry_after: true (wait at least retry-after)
ERROR P11 worst case 15 min 8 s is over the caller's deadline of 2 min 0 s
fix: set stop_at_deadline: true (no wait or attempt starts past the deadline, and an attempt's timeout is the time left), or cut attempts and timeout
ERROR P14 side effects are unsafe and the policy retries errors where the first try may have run (connection, timeout, 500, 504, 529, 5xx, 408): a retry can send, charge or write twice
fix: retry the model call, not the turn: run each side effect once, under an idempotency key your own system checks (idempotency_key: true)
WARN P6 multiplier 1: a fixed wait, not exponential backoff; every retry arrives as fast as the last
fix: use 2
WARN P9 no jitter: clients that failed together retry together, and fail together again
fix: use full jitter
WARN P13 stacked retries: 5 attempts here × (2 SDK retries + 1) = 15 requests for one call
fix: retry in one place: set the SDK's max_retries to 0 under your loop, or drop your loop
NOTE P3 retries 409 conflict_error; the docs say to resolve the conflict first, so a blind retry usually conflicts again
fix: retry 409 only after reading the resource's state
THE WAITS · base 2 s · ×1 per retry · cap 2 s · jitter none
before retry 1 2.00 s to 2.00 s (expected 2.00 s; longest waits so far 2.00 s)
before retry 2 2.00 s to 2.00 s (expected 2.00 s; longest waits so far 4.00 s)
before retry 3 2.00 s to 2.00 s (expected 2.00 s; longest waits so far 6.00 s)
before retry 4 2.00 s to 2.00 s (expected 2.00 s; longest waits so far 8.00 s)
WORST CASE · 5 attempts × (2 SDK retries + 1) × 1 min 0 s timeout + 8.0 s of waits = 15 min 8 s against a deadline of 2 min 0 s
REQUESTS · at most 15 for one call
VERDICT · FAIL · 10 ERROR · 3 WARN · 1 NOTE
[… 3 more lines, trimmed here]
RETRY TRACE · last-night.jsonl against team-policy.json · 5 calls · rules as read 2026-10-12
call T-1041 · succeeded · 5 attempts · 15.7 s
1 t= 0.0 s 429 rate_limit_error RETRY AFTER ra=12 waited=2.0 retried after 2.0 s; retry-after said 12.0 s
2 t= 2.4 s 429 rate_limit_error RETRY AFTER ra=10 waited=2.0 retried after 2.0 s; retry-after said 10.0 s
3 t= 4.8 s 429 rate_limit_error RETRY AFTER ra=7 waited=2.0 retried after 2.0 s; retry-after said 7.0 s
4 t= 7.2 s 429 rate_limit_error RETRY AFTER ra=5 waited=2.0 retried after 2.0 s; retry-after said 5.0 s
5 t= 9.6 s 200 - OK ra=- waited=-
call T-1042 · failed · 5 attempts · 9.5 s
1 t= 0.0 s 400 invalid_request_error NEVER ra=- waited=2.0 retried a 400 invalid_request_error
2 t= 2.3 s 400 invalid_request_error NEVER ra=- waited=2.0 retried a 400 invalid_request_error
3 t= 4.6 s 400 invalid_request_error NEVER ra=- waited=2.0 retried a 400 invalid_request_error
4 t= 6.9 s 400 invalid_request_error NEVER ra=- waited=2.0 retried a 400 invalid_request_error
5 t= 9.2 s 400 invalid_request_error NEVER ra=- waited=- stopped on a 400: right
call T-1043 · succeeded · 2 attempts · 14.1 s
1 t= 0.0 s 529 overloaded_error RETRY ra=- waited=2.0
2 t= 7.8 s 200 - OK ra=- waited=-
call T-1044 · succeeded · 2 attempts · 121.2 s
1 t= 0.0 s timeout - RETRY · AMBIGUOUS ra=- waited=2.0 a side effect ran, then the call was retried
2 t= 63.0 s 200 - OK ra=- waited=-
call T-1045 · failed · 2 attempts · 2.4 s
1 t= 0.0 s 429 rate_limit_error NEVER ra=- waited=2.0 retried a 429 rate_limit_error (the spend cap)
2 t= 2.2 s 429 rate_limit_error NEVER ra=- waited=- stopped on a 429 (the spend cap): right
FINDINGS
ERROR T2 call T-1041 · attempt 1: retried after 2.0 s though retry-after said 12.0 s; the docs say earlier retries will fail
ERROR T2 call T-1041 · attempt 2: retried after 2.0 s though retry-after said 10.0 s; the docs say earlier retries will fail
ERROR T2 call T-1041 · attempt 3: retried after 2.0 s though retry-after said 7.0 s; the docs say earlier retries will fail
ERROR T2 call T-1041 · attempt 4: retried after 2.0 s though retry-after said 5.0 s; the docs say earlier retries will fail
ERROR T1 call T-1042 · attempt 1: retried a 400 invalid_request_error, which fails the same way every time
ERROR T1 call T-1042 · attempt 2: retried a 400 invalid_request_error, which fails the same way every time
ERROR T1 call T-1042 · attempt 3: retried a 400 invalid_request_error, which fails the same way every time
ERROR T1 call T-1042 · attempt 4: retried a 400 invalid_request_error, which fails the same way every time
ERROR T5 call T-1044 · attempt 1: a side effect ran and the call was retried, so it may run twice
ERROR T8 call T-1044 · the call ran 121.2 s, past the caller's deadline of 120.0 s
ERROR T1 call T-1045 · attempt 1: retried a 429 rate_limit_error (the spend cap), which fails the same way every time
VERDICT · FAIL · 11 ERROR · 0 WARN · 0 NOTE
FORMULA · each failed attempt is classed by the error table; the wait = the logged wait_s, or the next attempt's start − this start − its duration; a retry before retry-after, a retry of a NEVER error or a retry after a side effect is an ERROR.
SOURCE · the log you gave; errors platform.claude.com/docs/en/api/errors; retry-after platform.claude.com/docs/en/api/rate-limits · read 2026-10-12.
LIMIT · without durations, the gap between starts includes the attempt itself, so an early retry can be missed but is never invented; HTTP-date retry-after values are not read.
THE SELFTEST, AS PRINTED
PASS the table: 400, 401, 402, 403, 404 and 413 are never retried; 500, 504, 529 and stream errors are
PASS a 429 with retry-after waits for it; the spend-cap 429 is never retried; a 429 with neither is flagged
PASS connection errors and timeouts are retryable but ambiguous; 502 is a 5xx; 422 is never retried
PASS a sound policy passes with no ERROR and no WARN
PASS retrying 'any' is an ERROR for each error that never clears, the spend cap included
PASS retrying 429 without honouring retry-after is an ERROR
PASS a fixed wait and no jitter are WARNs
PASS stacked retries: 5 attempts × (2 SDK retries + 1) = 15 requests
PASS unsafe side effects retried on ambiguous errors without a key are an ERROR
PASS the worst case of 15 tries of 10 minutes is over a 30 s deadline, an ERROR
PASS dropping 529 and connection errors is a WARN for each
PASS waits: base 1 s doubling to a 30 s cap gives 1, 2, 4, 8, 16 s (31 s in all)
PASS jitter ranges: full 0..d, equal d/2..d, decorrelated base..min(cap, base × 3^k)
PASS worst case: 4 × 600 s + 1 + 2 + 4 = 2,407 s; stop_at_deadline caps it at 30 s; an uncapped retry-after leaves it unbounded
PASS streaming without retrying stream error events is a WARN
PASS with an idempotency key the side-effect ERROR clears
PASS trace: a retried 400 is an ERROR
PASS trace: a retry 3 s after a retry-after of 20 s is an ERROR; waiting 18 s for 17 s is not
PASS trace: the spend-cap 429, read from the error body, retried, is an ERROR
PASS trace: a side effect followed by a retry is an ERROR
PASS trace: giving up after one 529 is a WARN; a call past its 30 s deadline is an ERROR
PASS simulate: the same seed gives the same numbers; ignoring retry-after sends retries that meet the 429 again, honouring it sends none
PASS simulate: under the spend cap nothing succeeds; retrying 'any' wastes 4 retries a call, a policy that stops on it wastes none
PASS a policy it cannot read exits 2 and names every bad field with what is allowed, never a crash
PASS the command line: a sound policy exits 0, a bad one 1; simulate writes a log that trace reads, call for call; --help shows usage
PASS the same policy gives the same report, byte for byte
PASS assets/api-rules.json matches the rules built into this machine
PASS nothing in this machine opens a network connection
selftest 28/28
THE TRIGGER TEST. The card's line was tried on Haiku, Sonnet and Opus beside 14 neighbouring skills, in a clean environment: 36/48 on its own prompts (Haiku 4/16 · Sonnet 16/16 · Opus 16/16), 0 wrong picks; no skill (answered directly) 12.
THE RUNS ARE PASTED FROM THE CARD’S OWN RECORD AS PRINTED. THE CASES ARE THE STUDIO’S OWN EXAMPLES (EXAMPLE CO IS FICTION); NO PRIVATE PERSON IS NAMED.
QUESTIONS AT THE TABLE
Asked before the wire.
What does it need from me?
Python 3; the retry policy as JSON, and an error log if there is one.
Does it send anything anywhere?
Its machine reads what you point it at, and HOSTS.md says what it needs; python 3; the retry policy as JSON, and an error log if there is one. The words run wherever an AI reads Markdown.
What is on the record?
The selftest (28/28), a run on a realistic case with every command and verdict pasted into WITNESS.md as printed (Example Co's nightly batch: its policy (10 ERROR, 15 requests a call), one night replayed (11 ERROR, an email sent twice), and the fixed policy; 39 of 48 in the trigger test after the rewrite); and the trigger test, the card's line tried on Haiku, Sonnet and Opus beside 14 neighbouring skills: 36/48 on its own prompts, 0 wrong picks; the twelve-check audit (AUDIT.md). The punch on the face is the SHA-256 of SKILL.md, so a downloaded copy can be checked against this room.
Can it be wrong?
Yes — it is an AI reading a text file. The policy as written, not the code that runs it; the error facts were read 2026-10-12 and change; a simulation is not a measurement.
What will it never do?
It refuses retry rules from memory; advising a retry of an error that never clears; presenting a simulation as a measurement; ignoring a side effect a retry would repeat.
Who may use it?
One person, any number of their own AIs and computers; a team needs a company licence.