@endstate-sdk/core raises is a typed error carrying the
information support needs. Retry behaviour is not guesswork either: it is
derived from the API spec at build time, so a call is retried only when
repeating it is safe.
Branch on the code
isEndstateError(error, ...codes):
The error types
All extend
EndstateError, which carries requestId, operationId, and
attempts. Log requestId on every failure - it is the fastest way for
support to find your request.
Which calls are retried
Retry eligibility comes from the spec, not from the method name. Every operation falls into one of three classes.
Two consequences worth internalizing:
A keyed write is never retried on a
5xx. The API clears its idempotency
record on any non-2xx, so a same-key retry would execute a second time instead
of replaying the first. The SDK will not do that for you.
Writes are never repeated at all. units.update,
collections.update, settings.update, settings.corsOrigins.replace,
sessionTokens.revoke, and testHelpers.createTap accept no idempotency key,
so the API cannot deduplicate them and a second send is a second write.
Raising maxAttempts does not change this, and that is not a bug. The single
exception is 429 rate_limit.exceeded, which the API refuses before any
handler runs, so nothing was written.
Where the idempotency key comes from
For a keyed create, the SDK sends anIdempotency-Key on your behalf. Which
key it sends determines whether a later run is safe, and error.safeToRetry
tells you which case you are in.
EndstateNetworkError and
EndstateTimeoutError - the two cases where you cannot know whether the write
landed - carry safeToRetry and the idempotencyKey that was used.
safeToRetry means “calling again recovers this same operation”. It is true
for a read, and for a write whose key is stable across calls - one you
supplied, or the one verify() derives from the tap. It is false when the
SDK generated the key, because a fresh call would generate a different one and
the API would treat it as a second write.
Pass the key back to recover the original:
Tuning it
Retries use equal-jitter exponential backoff and honourRetry-After.
Configure per client or per call:
DEFAULT_RETRY_POLICY is what applies when you set none - spread it to change
one field without restating the rest:
onRequest, onResponse, and onRetry:
reason is one of network, timeout, rate_limited, server_error, or
idempotency_in_progress.
