@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.shruns in CI and fails the build on any barethrow new Error(...)inpackages/core/src/.
Pattern
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:
| Property | Type | Meaning |
|---|---|---|
code | KitErrorCode | One of the ten codes below. |
message | string | Default human-readable summary (may be overridden by the caller). |
cause | unknown | Original exception when one was wrapped (e.g. a DOMException). |
fallback | string | Recommended 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.