Give up early (BailError)
The problem
Some failures aren't worth a single retry — a 404, a 400, an auth error. And sometimes the decision depends on the response, not just an exception: you read the body, see it's hopeless, and want to stop now, no waiting.
shouldRetry only sees the error, which isn't always enough.
The solution
Throw a BailError from inside fn. It stops immediately and rejects with the wrapped cause — skipping the wait, shouldRetry, every remaining attempt and even forever.
ts
import retry, { BailError } from 'promise-fn-retry';
const data = await retry(
async (attempt) => {
const res = await fetch('/api/things');
if (res.status === 404) throw new BailError(new Error('Not found')); // give up now
if (!res.ok) throw new Error('Transient failure'); // retried
return res.json();
},
{ times: 5 },
);The outer promise rejects with whatever you passed to new BailError(cause) — the BailError itself never leaks out.
Try it
Set bailAt to an attempt number and watch it stop dead there, regardless of how many retries remain.
attempt timelineidle
- failed
- timed out
- bailed
- pending
- succeeded
The purple marker is the bail — no wait, no further attempts.
- Press Run to start.