Crossdeck Docs
Pricing Dashboard

Error codes

Reference 5 min read · Updated May 11, 2026

Every CrossdeckError the SDK can throw. Each entry has a stable code string, a human description, a one-sentence resolution, and a retryable flag indicating whether the SDK auto-recovers (no developer action needed) or whether the failure requires intervention. Same surface Stripe ships at stripe.com/docs/error-codes.

TL;DR

CrossdeckError shape

import { CrossdeckError } from "@cross-deck/web";

try {
  await Crossdeck.identify("");
} catch (err) {
  if (err instanceof CrossdeckError) {
    err.type;        // "invalid_request_error"
    err.code;        // "missing_user_id"
    err.message;     // human-readable
    err.requestId;   // server-issued; quote in support tickets
    err.status;      // HTTP status if the error came from an API response
    err.retryAfterMs;// server's Retry-After when present
  }
}

Seven distinct type values group errors into broad categories:

typeWhat it means
authentication_errorBad API key, missing key, expired key. Server rejected the credential.
permission_errorKey is valid but not authorised for the operation (e.g. wrong origin, wrong project).
invalid_request_errorMalformed input — missing required field, invalid format, etc.
rate_limit_errorToo many requests. Honour the retryAfterMs field.
network_errorFailure at the transport layer — DNS, TCP, TLS, timeout, abort.
internal_errorCrossdeck-side bug or transient outage. Server-issued.
configuration_errorWrong init options — caught client-side at Crossdeck.init().

Configuration errors

Thrown synchronously by Crossdeck.init(). Not retryable — fix the init options.

codeDescriptionResolution
invalid_public_key The publishable key passed to Crossdeck.init() doesn't start with cd_pub_. Copy the key from your Crossdeck dashboard → API keys page.
missing_app_id Crossdeck.init() was called without an appId. Add appId to your init options — find it in the dashboard's Apps page.
invalid_environment Crossdeck.init() requires environment: "production" | "sandbox". Pass the literal string "production" or "sandbox" — no other values are accepted.
environment_mismatch The publishable key's env prefix doesn't match the declared environment option. Either change environment to match the key prefix (cd_pub_test_ ↔ sandbox, cd_pub_live_ ↔ production), or swap the key.
not_initialized An SDK method was called before Crossdeck.init(). Call Crossdeck.init({ appId, publicKey, environment }) once at app startup before any other method.

Validation errors

Thrown when SDK method arguments don't meet the contract. Not retryable — fix the call site.

codeDescriptionResolution
missing_user_id identify() was called with an empty userId. Pass a stable, non-empty user identifier from your auth layer — never a hardcoded placeholder.
missing_event_name track() was called without an event name. Pass a non-empty string as the first argument.
missing_group_type group() was called without a group type. Pass a non-empty type (e.g. "org", "team") as the first argument.
missing_signed_transaction_info syncPurchases() was called without StoreKit 2 signed transaction info. Pass the JWS string from Transaction.currentEntitlements / Transaction.updates.

Network errors

Transport-layer failures. Retryable — the SDK's built-in exponential-backoff retry handles them automatically for the event queue. Manual API calls (identify, getEntitlements, syncPurchases) surface them to the caller.

codeDescriptionResolution
fetch_failed The underlying fetch() call failed (typically a network outage or DNS issue). Check the user's network. The SDK will retry automatically with exponential backoff (1s → 60s with jitter, capped at maxMs).
request_timeout A request was aborted after the configured timeoutMs (default 15s). Check the user's connection. Increase timeoutMs in init options if the user is on a known-slow network.

Internal errors

Crossdeck-side bugs or transient outages.

codeDescriptionResolution
invalid_json_response The server returned a 2xx response with an unparseable body. Likely a transient backend bug. Retry; if it persists, contact support with the requestId.

Full table

The complete reference, sorted by type. The SDK exports the same list at runtime as CROSSDECK_ERROR_CODES, and ships it as a sidecar JSON for tooling.

import { CROSSDECK_ERROR_CODES, getErrorCode } from "@cross-deck/web";

CROSSDECK_ERROR_CODES;
// → ErrorCodeEntry[] — same shape as the table above

getErrorCode("environment_mismatch");
// → { code, type, description, resolution, retryable }
code type retryable Resolution summary
invalid_public_keyconfiguration_errorNoCopy the key from the dashboard.
missing_app_idconfiguration_errorNoAdd appId from the Apps page.
invalid_environmentconfiguration_errorNoPass "sandbox" or "production".
environment_mismatchconfiguration_errorNoReconcile key prefix with declared env.
not_initializedconfiguration_errorNoCall init() before any other method.
missing_user_idinvalid_request_errorNoPass a non-empty userId.
missing_event_nameinvalid_request_errorNoPass a non-empty event name.
missing_group_typeinvalid_request_errorNoPass a non-empty group type.
missing_signed_transaction_infoinvalid_request_errorNoPass the JWS from StoreKit 2.
fetch_failednetwork_errorYesSDK retries automatically.
request_timeoutnetwork_errorYesCheck network or increase timeoutMs.
invalid_json_responseinternal_errorYesRetry; contact support with requestId if persistent.

Server-side errors that come back via the API (rate limits, permission denials, validation failures) follow Stripe's envelope format — { error: { type, code, message, request_id } } — and surface as CrossdeckError with the appropriate status. The code values for those are issued server-side and may extend the list above.

Machine-readable JSON

For AI assistants, error-aggregator dashboards, and any tooling that wants the table without booting a JavaScript runtime, the SDK ships a sidecar JSON file in the npm tarball:

node_modules/@cross-deck/web/dist/error-codes.json

Shape:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "generatedAt": "2026-05-11T11:23:00.000Z",
  "sdk": "@cross-deck/web",
  "codes": [
    {
      "code": "environment_mismatch",
      "type": "configuration_error",
      "description": "The publishable key's env prefix doesn't match the declared environment option.",
      "resolution": "Either change `environment` to match the key prefix (cd_pub_test_ ↔ sandbox, cd_pub_live_ ↔ production), or swap the key for one minted in the right env.",
      "retryable": false
    },
    ...
  ]
}

It is also reachable via the unpkg CDN at https://unpkg.com/@cross-deck/web@1.0.0/dist/error-codes.json for tooling that doesn't pull the package into its dependency tree.

Handling errors in app code

Two patterns. Pick by intent.

Catch a specific code for recovery

try {
  await Crossdeck.identify(userId, { traits });
} catch (err) {
  if (err instanceof CrossdeckError && err.code === "environment_mismatch") {
    // Re-init with the right env, or surface a developer-facing toast.
  } else {
    // Unknown error — surface generically + log.
    console.error("identify failed:", err);
  }
}

Branch by category for broad strokes

if (err instanceof CrossdeckError) {
  switch (err.type) {
    case "authentication_error":
      // API key is bad — alert the developer, not the user.
      break;
    case "rate_limit_error":
      // Honour err.retryAfterMs — back off.
      break;
    case "network_error":
      // Transient. SDK auto-retries the event queue; manual calls fail.
      break;
  }
}
You don't have to catch errors from track().

Crossdeck.track() is fire-and-forget and synchronous. It never throws on a network failure — that's the queue's job. The only way track() throws is the validation case missing_event_name, which is a programmer error caught the moment you call track("").


This list reflects @cross-deck/web@1.0.0. New codes added in future releases will appear here in lockstep with the SDK source at sdks/web/src/error-codes.ts.