Errors
Direct HTTP integrations receive standard status codes plus SkyState error bodies where applicable. The JavaScript SDKs translate these into SkyStateError values, subsystem status snapshots, and React onError callbacks depending on where the error occurs.
Common situations that result in errors:
- Route target not found - the project or account route identifier is not recognized; an invalid environment value (not one of
development,staging,production) returns400instead - No state yet - public-state and user-state reads can return
204; SDK keyed reads continue to use their fallback value - Quota exceeded - the account's monthly API-request quota or another tier limit has been reached; see Rate Limiting
- Authentication failure - the API key is invalid or has been revoked; see Dev API Keys
- Version conflict - a write precondition failed and returned
412: an update sent a stale or missingIf-Matchversion, anIf-None-Match: *create found that state already exists, or the write usedIf-Match: "0", which always fails - Quota failure - a write would exceed a tier limit, such as the Stored Users limit for user state
- Service unavailable - the API could not reach its database and returned
503; the response carriesRetry-After: 5and the request can be retried unchanged; see Retry-After
SDK error codes
The SDK translates failures into typed SkyStateError values with a code: SkyStateErrorCode field. The full code list and HTTP-status-to-code mapping are below; the canonical mapping (Section 8.5) lives in the repository specification document (docs/3_specification.md).
authentication- token refresh rejected, a401/403on a signed-in request, or a write attempted without sign-inconfiguration- unknown account, project, or environment slug (404); retried, so a fixed slug heals without a reloadquota- monthly request quota or tier limit exceeded (402); the SDK keeps queued writes and retries at a slow pace. A monthly-quota402setsRetry-Afterto the seconds until the monthly counter resets (readable cross-origin) and includes aresetAtISO timestamp in the bodyrate_limited- per-minute rate limit exceeded (429)server_unavailable-5xxresponse; retried on the SDK's own backoff. A503means the API could not reach its database and carriesRetry-After: 5, readable cross-origin; the SDK does not read the header on5xx- see Retry-Afterprotocol- a response the SDK could not interpret: an unexpected status or a malformed bodyno_response- no HTTP response at all (offline, DNS failure, timeout, CORS); retriedmissing_config,missing_provider,disposed- programmer misuse; thrown synchronously at the call siteinvalid_path- an invalid state key or non-JSON write value. Detected at the call site it throws synchronously; a deferred updater failure caught at drain time is instead reported viaonErrorand pinned as a permanent health errorpatch_invalid,patch_unsupported_operation,patch_invalid_path,patch_missing_value,patch_path_untraversable,patch_invalid_array_index,patch_invalid_state_root,patch_state_too_large- the server rejected that specific write (400); the SDK drops it and continues the queue
There is no conflict code: a 412 version race is reconciled inside the SDK (refetch and replay) and never surfaces as an error.
Alongside code and message, variants carry extra fields:
httpStatus- on errors that arrived as an HTTP response; absent onno_responseand the misuse codes. Onauthenticationit isnumber | null, because auth can fail before any HTTP response is receivedpath- the user-state key a keyed write was for; always set on write rejections andinvalid_path,string | nullon other request errors, absent on the sync-thrown misuse codesretryAfter- onrate_limitedonly: the server'sRetry-Afterdelay in seconds, ornullwhen the header was absent or unreadable
Retrying applies to the background loops: public-state loads, user-state reads and writes, and token refresh. The one-shot code exchange during sign-in is not retried, so a failure there surfaces once and halts the callback.
Retries back off with jitter: the first retry comes roughly 1-5 seconds after the failure, rising to a steady state of roughly 2.5-5 minutes between attempts. quota errors are paced slower: a jittered 2.5-5 minutes at first, doubling up to a 30-minute ceiling. A rate_limited response honors the server's Retry-After, capped at 30 minutes.
For SDK-specific error handling, see the SDK docs.