Skip to content
Systems

The retriable request

One retry, on a fresh connection, for transport errors only. The harness's fetch rule, explained — and why 'only' is doing the heavy lifting.

Intermediate1 min read (computed · recorded 7)updated 2026-09-12reliabilityhttpharness

by Motif Editors

revised 2026-09-12First publication in bank-3 batch 4.

Key takeaways
  • Retry transport errors once, on a fresh connection — never 4xx.
  • Idempotency is designed server-side before the client retries.
  • A second failure is real; let it throw.

What a retry may undo

A GET retries safely. A POST retries a side effect: two orders, two emails, two everything. Idempotency is the property that makes retry boring, and it is designed server-side before the client's backoff loop is written.

The one-retry rule

The harness fetches hundreds of pages through a keep-alive pool; the server closing an idle socket arrives as a socket error, not a status. One retry on a fresh connection recovers exactly that population — and a second failure is real, so it throws.

The discipline is in the 'only': retry transport errors, never 4xx. A 404 on the second attempt is the same 404, and retrying it doubles the embarrassment.

the rule, in full
const fetchRetry = async (url, init, attempt = 1) => {
  try { return await fetch(url, init) }
  catch (err) {           // transport only — a 404 never lands here
    if (attempt < 2) return fetchRetry(url, init, attempt + 1)
    throw err
  }
}
Practise the lesson

Theory sticks when you ship it. These original Motif assets put this guide's lesson to work — open one and copy it into your own page.