VRPlatformVRPlatform
Run in Production

Errors & Retries

Retry transport safely and turn business failures into repair actions

Use HTTP status for transport class and structured code, issues, and context for program behavior. Never parse message.

FailureDefault action
Schema or business validationCorrect payload; do not retry unchanged
AuthenticationCorrect credential or expiry; do not rotate teams automatically
Permission or scopeCorrect access assignment or selected team
Lock or conflictRe-read current state and show documented recovery
429Respect Retry-After; webhook administration enforces quotas
Transient 5xx / availabilityRetry idempotently with jitter
External provider failureRead connection/sync state before another action
Webhook recipient failureFollow durable delivery retry and replay contract

Webhook subscription, test, and replay operations can return 429 when their documented quota is exceeded. Respect Retry-After and retry with bounded backoff. Other API surfaces do not currently enforce application-level quotas, although infrastructure can still return a rate-limit response.

Idempotency

Use stable external references where the operation documents them. A retry must not invent a new source identity or persist IDs returned by dry run. For a write whose outcome is uncertain, read current state before retrying when no idempotency key exists.

The TypeScript client (@vrplatform/api) automatically retries GET, HEAD, and OPTIONS requests with up to five attempts by default. Set attempts to change that read limit, including attempts: 1 to disable read retries. Writes are attempted once, even when attempts is larger. Custom assertResponse validation runs on that attempt unless assertOnLastAttempt is explicitly false. Assertion failures never replay the write. There is no automatic write-retry opt-in. Reconcile an uncertain write before another request; a session ID does not deduplicate a business operation.

TypeScript Error Handling

throwIfError(response) and await throwIfError(responsePromise) preserve the same public envelope in ApiClientError.error. The error also exposes code, issues, context, links, and retryable directly. Narrow the unknown context before reading recovery fields, or use the endpoint's generated error response type.

An HTTP failure with malformed JSON, an empty body, or a missing public error envelope throws ApiClientResponseError, whose status is the HTTP status. It has no public error code. A 503 alone does not identify worker resource exhaustion. Transport rejections remain transport errors.

Backoff

Bound retries, add jitter, and stop on deterministic 4xx failures. Alert on exhaustion with correlation ID, route, team, structured error code, and safe context. Never log API keys, bearer tokens, or webhook secrets.

An exhausted database socket connection attempt returns 503 SERVICE_UNAVAILABLE with the static message Database connection is unavailable. This response does not include a blanket retryable flag or Retry-After header. Retry reads with bounded backoff; reconcile a write's outcome before repeating it.

For a known database connection loss after dispatch, including a severed Hyperdrive egress response or an established connection loss, the API retries only compiled select operations. Mutations and raw or unknown queries remain single-attempt because their outcome may be unknown. A caller receiving 503 SERVICE_UNAVAILABLE must therefore reconcile a write before retrying it unless the complete operation is idempotent or has stable source identity.

Webhook delivery uses its own documented application schedule; do not add a second aggressive retry loop at the recipient.

See Error Contract and Webhooks.

On this page