QuantumNous/new-api · error · Error
Failed to complete Passkey login
Error message
Failed to complete Passkey login
What it means
Thrown in the Passkey sign-in flow when finishPasskeyLogin — the POST that submits the signed WebAuthn assertion with the flow_token — returns success:false without a handled server message key. The fallback text is 'Failed to complete Passkey login'; the server's own message wins when present. This is a server-side verification failure of the assertion.
Source
Thrown at web/src/features/auth/sign-in/components/user-auth-form.tsx:291
const credential = (await navigator.credentials.get({
publicKey,
})) as PublicKeyCredential | null
if (!credential) {
toast.info(t('Passkey login was cancelled'))
return
}
const assertion = buildAssertionResult(credential)
if (!assertion) {
throw new Error(t('Invalid Passkey response'))
}
const finish = await finishPasskeyLogin(flowToken, assertion)
if (!finish.success) {
if (getServerErrorMessageKey(finish)) return
throw new Error(finish.message || t('Failed to complete Passkey login'))
}
if (!isAuthBundle(finish.data)) {
throw new Error(t('Missing user data from Passkey login response'))
}
await handleLoginSuccess(finish.data, redirectTo)
toast.success(t('Signed in with Passkey'))
} catch (error: unknown) {
if (getServerErrorMessageKey(error)) return
if (error instanceof DOMException && error.name === 'NotAllowedError') {
toast.info(t('Passkey login was cancelled or timed out'))
} else if (error instanceof Error) {
toast.error(error.message)
} else {
toast.error(t('Passkey login failed'))
}
} finally {View on GitHub (pinned to e2c7aa7b10)
Solutions
- Read finish.message from the response — the backend states the verification failure reason.
- Retry the whole Passkey flow promptly (fresh challenge + flow_token); most failures are stale-token timing issues.
- If it persists for one device, re-register the passkey (delete then add) — server-side credential state may be stale.
- Check server logs/clock sync if all users are affected.
Defensive patterns
Strategy: retry
Try / catch
try {
const finish = await finishPasskeyLogin(flowToken, assertion)
if (!finish.success) {
if (getServerErrorMessageKey(finish)) return
throw new Error(finish.message || t('Failed to complete Passkey login'))
}
} catch (error) {
if (getServerErrorMessageKey(error)) return
if (error instanceof DOMException && error.name === 'NotAllowedError') {
toast.info(t('Passkey login was cancelled or timed out'))
} else {
toast.error(error instanceof Error ? error.message : t('Passkey login failed'))
}
} Prevention
- Finish the WebAuthn ceremony quickly — stale flow tokens are the top cause
- If a device keeps failing verification, re-register its passkey
- Keep server clocks NTP-synced for challenge validity windows
When it happens
Trigger: POST finish-passkey-login returns success:false: challenge mismatch, expired flow_token, unknown credential ID, signature verification failure, or clock skew between server and authenticator.
Common situations: User left the WebAuthn prompt open until the flow_token expired; credential deleted server-side but still present in the browser; backend RPC to the WebAuthn verifier failing; server time drift breaking challenge timestamps.
Related errors
- Unable to parse Passkey login options from response
- Failed to start Passkey login
- Passkey verification is not supported in this environment
- Failed to start verification
- Verification flow expired
AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15).
Data as JSON: /api/errors/a15392e474ea4694.
Report an issue: GitHub.