Errors & Troubleshooting
Use error codes when you have them; use symptoms when you do not.
On this page
Error shape
Partner API errors return JSON: { "error": string, "message": string, "details"?: object }. TypeScript SDK maps many cases to typed errors; others surface as KeyraServerError with .status, .code, and .body.
API error codes
| Error | HTTP | Meaning | Common cause | Fix |
|---|---|---|---|---|
invalid_client | 401 | Bad credentials | Wrong clientId/secret or publishable key used as secret | Use secret key; format Bearer clientId:clientSecret |
not_enrolled | 404 | No active identity | Challenge before enrollment / after revoke | Run enable2FA first |
already_enrolled | 409 | Identity already active | Calling enroll twice | Use status check; go to challenge flow |
already_consumed | 409 | Token reused | Double consume / retry without new challenge | Create new challenge for a new login |
invalid_token | 401 | Wrong verification token | Stale/mismatched token | Use token from the approved poll for that challengeId |
expired | 401/410 | Token or link expired | Waited too long after approval / enrollment | Restart enrollment or challenge |
not_found | 404 | Unknown id | Bad enrollment/identity/challenge id | Verify ids; check project scope |
invalid_return_url | 400 | returnUrl rejected | Missing callback config / origin mismatch | Align returnUrl with project callback URL |
invalid_request | 400 | Validation failed | Bad projectId UUID / externalUserId | Fix request body (externalUserId ≤ 128) |
forbidden | 403 | Project mismatch | Consume across projects | Use credentials for the challenge's project |
rate_limited | 429 | Too many requests | Aggressive polling / abuse | Honor pollAfterMs; back off |
SDK exceptions (TypeScript)
| Class | When | Retry? |
|---|---|---|
KeyraAuthenticationError | HTTP 401 invalid_client | No — fix credentials |
KeyraTimeoutError | wait helpers exceeded timeout | Optional — start a new challenge/enrollment |
KeyraChallengeDeniedError | status denied | Yes — new challenge after user retry |
KeyraChallengeExpiredError | status expired | Yes — new challenge |
KeyraEnrollmentExpiredError | enrollment terminal EXPIRED | Yes — new enable2FA |
KeyraEnrollmentCancelledError | CANCELLED | Yes — new enable2FA |
KeyraEnrollmentFailedError | FAILED (e.g. revoked/suspended identity) | Investigate identity state |
KeyraIdentityError | disable/recovery/codes with no identity | Enroll first |
KeyraNetworkError | Transport/timeout | Transient — retry with backoff |
KeyraServerError | Other non-2xx | Inspect .code / status |
Troubleshooting by symptom
Enrollment QR opens but nothing completes
- Possible cause: User abandoned flow; enrollment expired (10 minutes); polling wrong enrollmentId.
- Diagnose:
pollEnrollmentstatus /terminal. - Fix: Start a new
enable2FA; ensure UI polls the same id.
Challenge remains PENDING
- Possible cause: User has not opened QR; wrong URL shown; challenge already expired.
- Diagnose: Confirm
challengeUrlencoding; check expiresIn; poll status. - Fix: Re-display QR quickly; start a new challenge if expired.
User approved but login doesn't complete
- Possible cause: Backend never called consume; lost
verificationTokenby re-polling; started a new challenge on “complete”. - Diagnose: Log challengeId continuity; ensure consume runs once with token from wait helper.
- Fix: Reuse challengeId → wait → consume → then create your session.
Challenge expired
- Possible cause: User took longer than ~2 minutes.
- Fix: Start a new challenge; improve UX messaging.
Identity shows as not enrolled
- Possible cause: Never enrolled; disabled/revoked; different
externalUserId/ project. - Fix: Verify projectId + externalUserId stability; re-enroll.
401 from Partner API
- Possible cause: Incorrect Bearer format; sandbox/prod mix; using only
sk_*withoutclientId:prefix. - Fix:
Authorization: Bearer cp_…:sk_…with matching environment.
Works locally but fails in production
- Possible cause: Still using
_test_keys; returnUrl/callback mismatch; wrong base URL. - Fix: Switch to
cp_prod_/sk_prod_and production projectId; verify callback configuration.
