RateLimitError
The delegate-backoff error: a rate-limit response surfaced for an outer gate to back off on, instead of being retried internally.
What you'll see
A stitch with rateLimit: { delegate: true }
that gets a rate-limit response (status in rateLimit.on, default [429])
rejects with a RateLimitError instead of retrying. Unlike most failures,
this is not a StitchError — it's its own exported class, so you can catch it
specifically and hand the signal to whatever owns your backoff:
import { , } from 'stitchapi';
const = ({
: 'https://api.example.com',
: '/pages/{id}',
: { : true },
});
try {
await ({ : { : '42' } });
} catch () {
if ( instanceof ) {
.(.); // 429 (the rate-limit status that was hit)
.(.); // ms parsed from Retry-After, or undefined
.(..); // the raw response, for other rate headers
}
}RateLimitError carries:
status— the rate-limit status (e.g.429, or whatever you listed inrateLimit.on).retryAfterMs— the wait the server asked for, parsed fromRetry-After(delta-seconds or an HTTP-date) into milliseconds;undefinedwhen the header is absent or unparseable.response— the rawAdapterResponse, so you can read other rate headers the API sent (X-RateLimit-Remaining, a reset timestamp, and so on).
Why it happens
You opted into delegate-backoff because an outer gate or circuit — not StitchAPI — owns the rate budget. So when the API returns a rate-limit status, the stitch deliberately does not retry it and does not pace it on the internal throttle: it surfaces the outcome so your gate can apply the backoff, persist it, and decide when to release. This is the mode working as designed, not a new failure — the rate limit reached you on purpose.
How to handle it
- Feed it to your outer gate. Use
retryAfterMs(falling back to your own default when it'sundefined) to set the gate's penalty window, then let the gate gate the next attempt. That's the whole point of delegating. - Read it off the stream instead. If you consume
the event stream rather than awaiting, the same
outcome arrives as an
errorevent carryingstatusandretryAfterMs— notry/catchneeded. - Branch without throwing.
.safe()returns the failure as aStitchErrorwhose.statusis the rate-limit status and whose.causeis the originalRateLimitError(soretryAfterMsis still reachable via the cause). - Reconsider whether to delegate. If nothing outside StitchAPI actually
owns the backoff, you probably want internal handling instead — drop
rateLimitand use retry + throttle.