Skip to content

@stellar-passkey/core error taxonomy

Every failure in @stellar-passkey/core throws a KitError with a stable machine-readable code. Callers MUST branch on code (never on message, which is human copy and may change). The ten codes below are the complete universe; adding one is a minor-version bump, renaming or removing one is a major-version break.

Implementation: packages/core/src/errors.ts. Enforcement: scripts/check-error-taxonomy.sh runs in CI and fails the build on any bare throw new Error(...) in packages/core/src/.

Pattern

ts
import { KitError } from "@stellar-passkey/core";

try {
  await createPasskey({ /* … */ });
} catch (err) {
  if (err instanceof KitError) {
    switch (err.code) {
      case "USER_CANCELLED":         /* show "try again" UI */ break;
      case "ES256_NOT_SUPPORTED":    /* show "use a different device" UI */ break;
      case "RP_ID_MISMATCH":         /* report a config bug */ break;
      // …
      default: throw err; // never silently swallow an unknown code
    }
  } else {
    throw err;
  }
}

The error object also carries:

PropertyTypeMeaning
codeKitErrorCodeOne of the ten codes below.
messagestringDefault human-readable summary (may be overridden by the caller).
causeunknownOriginal exception when one was wrapped (e.g. a DOMException).
fallbackstringRecommended next action — surfaced via the KIT_ERROR_META map.

Codes

USER_CANCELLED

The user explicitly cancelled the WebAuthn prompt (clicked Cancel, dismissed the system dialog) or no authenticator was available.

Fallback: Retry the action. If cancellation was unintentional, ensure no other app is grabbing biometric input.

Typical sources: DOMException("…","NotAllowedError"), DOMException("…","AbortError") from navigator.credentials.create/get.

ES256_NOT_SUPPORTED

The authenticator does not advertise ES256 (COSE alg: -7, secp256r1). The Soroban host can only verify secp256r1, so there is no fallback.

Fallback: Try a different device or browser. Apple, Chrome, and Firefox all support ES256; some legacy Windows Hello stacks do not.

Typical sources: DOMException("…","NotSupportedError").

RP_ID_MISMATCH

The configured rpId does not match window.location.hostname (or a registrable parent of it), or one of the related RP fields (rpName, userName, userId size) is invalid.

Fallback: Set rpId to the eTLD+1 of the current hostname, or run the app from a hostname that matches the configured rpId.

Typical sources: Empty/oversized fields rejected by buildCreateOptions; DOMException("…","SecurityError") from navigator.credentials.create.

ORIGIN_MISMATCH

clientDataJSON.origin is not in the application's allow-list. Always indicates a configured/deployment mismatch — either the URL or the SDK config drifted.

Fallback: Verify the deployed URL and the application's expectedOrigin setting in parseClientDataJSON.

CHALLENGE_MISMATCH

The signed challenge (or the clientDataJSON envelope around it) does not match what the SDK expected. Covers: bytewise challenge disagreement, JSON parse failure, missing or non-string challenge field, malformed base64url, wrong ceremony type (webauthn.get vs webauthn.create).

Fallback: Retry the signing flow. Persistent failure usually means the SDK and contract are out of sync — file a bug.

INVALID_SIGNATURE_DER

ECDSA signature bytes are malformed. Covers both ASN.1 DER (30 LL 02 …) parsing failures and raw 64-byte r ‖ s shape errors (wrong length, etc.).

Fallback: Re-run the ceremony. Persistent failure usually points at a passkey-on-the-wire bug — file a bug with the captured assertion.

INVALID_PUBLIC_KEY

The authenticator returned a public key that is not a valid 65-byte SEC-1 uncompressed P-256 point (0x04 ‖ X ‖ Y).

Fallback: Re-register the credential. If it repeats, the authenticator is misbehaving — try a different device.

CONTRACT_AUTH_FAILED

The on-chain Soroban wallet rejected the authentication. Includes: signer-not-found (NotFound from __check_auth), session-signer scope violation (NotPermitted), and signature-verify failure (host secp256r1_verify panic).

Fallback: Confirm the signer is registered with the wallet (re-add it if necessary) and that the signature is well-formed (low-S normalized, correct credential id).

NETWORK_ERROR

A network call to Soroban RPC, Horizon, or any other endpoint failed.

Fallback: Check connectivity. Retry with exponential backoff. If the issue is sustained, switch RPC providers.

UNSUPPORTED_AUTHENTICATOR

WebAuthn / Web Crypto is not available in this environment. Reported when navigator.credentials is missing, crypto.subtle is missing, crypto.getRandomValues is missing, the page is served over plain HTTP, or a ceremony helper is not yet implemented in this kit version.

Fallback: Run from a secure context (HTTPS or localhost) in a modern browser. Server-side use is not supported.

Migration history

  • YK-251 (this issue): taxonomy frozen to the ten codes above. Old codes (CONFIG_ERROR, WEBAUTHN_NOT_ALLOWED, WEBAUTHN_UNSUPPORTED, SIGNATURE_INVALID, INTERNAL_ERROR, SIGNER_NOT_FOUND, NOT_PERMITTED, RPC_ERROR) collapsed into the codes above as documented in YK-251's Linear comment.

MIT — SCF-43 RFP submission (2026). Status: pre-1.0.