Troubleshooting
Quick fixes for the most common integration errors.
origin_not_allowed
Error: { "code": "origin_not_allowed" }
HTTP: 403
Your app’s origin is not in the allowed origins list for your Application.
Fix:
- Open the dashboard
- Go to Applications → your app → Allowed Origins
- Add your origin exactly as it appears (e.g.,
https://myapp.com) - For local development, add
http://localhost:PORT
In sandbox mode, origin validation is skipped. This error only appears in production mode.
session_expired
Error: { "code": "session_expired" }
HTTP: 400
The WebAuthn challenge expired before the user completed the ceremony. Challenges are valid for 10 minutes.
Fix:
- Call
register/startorauth/startagain to get a fresh challenge. - If your users are slow to respond, consider showing a “Session expired, please try again” message and auto-retrying.
NotAllowedError (browser)
Error: DOMException: NotAllowedError
Source: Browser WebAuthn API
The user cancelled the passkey prompt, or the browser blocked the ceremony.
Common causes:
- User clicked “Cancel” on the passkey dialog
- Page is not served over HTTPS (required except
localhost) - The RP ID doesn’t match the page’s domain
- Browser doesn’t support WebAuthn (very rare in 2026)
Fix:
- Catch this error and show a friendly “Try again” message:
const result = await client.authenticate({ externalUserId }); if (!result.ok && result.error.code === 'USER_CANCELLED') { showMessage('Authentication cancelled. Click to try again.'); }
SecurityError (browser)
Error: DOMException: SecurityError
Source: Browser WebAuthn API
WebAuthn requires a secure context.
Fix:
- Use HTTPS in production (required).
http://localhostandhttp://127.0.0.1are allowed for development.- For mobile testing over local network, use a tunnel. See Mobile Testing.
credential_not_found
Error: { "code": "credential_not_found" }
HTTP: 404
The passkey the user tried to authenticate with is not registered in TryMellon, or was revoked.
Common causes:
- User registered on a different device/browser
- Credential was revoked via dashboard or API
- The
external_user_iddoesn’t match the registered user
Fix:
- Prompt the user to register a new passkey
- Check credential status in the dashboard under Credentials
- Use the email fallback flow for account recovery
rate_limit_exceeded
Error: { "code": "rate_limit_exceeded" }
HTTP: 429
You’ve exceeded the rate limit for this endpoint.
Limits:
| Endpoint | Limit |
|---|---|
| General API | 100 req/min per IP |
| Email OTP | 3 per user/hour, 5 per email/hour |
| Cross-device init | 30 req/min per IP |
| Cross-device status | 20 req/min per session |
Fix:
- The SDK handles retries with exponential backoff automatically.
- Check the
X-RateLimit-RemainingandX-RateLimit-Resetheaders. - If you consistently hit limits, contact us about upgrading.
Passkey not appearing in autofill
The browser’s passkey autofill (Conditional UI) requires specific conditions.
Requirements:
- An
<input autocomplete="username webauthn">field on the page - The SDK’s
conditionalUIoption must be enabled - Browser must support Conditional UI (Chrome 108+, Safari 16+, Firefox 122+)
Fix:
<input type="text" autocomplete="username webauthn" />
client.authenticate({ conditionalUI: true });
SANDBOX_SESSION_TOKEN in production
If you’re seeing SANDBOX_SESSION_TOKEN values in production, your app
is still in sandbox mode.
Fix:
- Set
sandbox: falsein your SDK configuration - Use real Application credentials (App ID + Client ID)
- Ensure your origin is in the allowed origins list