LayerZeroFault
passkey recovery

WebAuthn Resident Key Credential Overflow

VV

Written by

Published:

Technical Guide

To resolve WebAuthn Resident Key Credential Overflow, resolve hardware security key and TPM credential overflow errors when creating WebAuthn passkeys. Manage discoverable credentials and storage limits. Ensure all derivation paths, environment parameters, and cryptographic signatures are verified client-side using deterministic tools before broadcasting live transactions.

When deploying or creating ERC-4337 Smart Accounts powered by WebAuthn passkeys (such as Coinbase Smart Wallet, ZeroDev Kernel, or Safe), hardware security keys like YubiKey (5 Series, 5Ci, Bio), Google Titan, or Feitian ePass provide the highest tier of private key security.

However, power users who secure multiple dApps, exchanges, and enterprise logins frequently encounter an abrupt failure during the passkey enrollment ceremony:

DOMException: The operation failed for an unknown reason.
[Status: OperationError]

or in Chromium developer consoles:

NotAllowedError: The operation either timed out or was not allowed. 
[CTAP2 error: 0x3A - CTAP2_ERR_KEY_STORE_FULL]

If your passkey issues are instead related to Windows Hello biometric lockout, see our dedicated guide on Fixing Windows Hello TPM Passkey Enclave Lock.


Technical Cause: FIDO2 Discoverable Credential NVRAM Constraints

Unlike software passkeys (iCloud Keychain, Google Password Manager, 1Password) which synchronize credentials to virtually limitless cloud databases, hardware security keys utilize isolated cryptographic microcontrollers with dedicated Non-Volatile RAM (NVRAM).

In the FIDO2 / CTAP2.1 specification, credentials fall into two categories:

  1. Non-Resident Keys (Server-Side Credentials): The private key is encrypted inside the credentialId using a master secret on the key. The key stores zero bytes on the device, allowing unlimited credentials.
  2. Resident Keys (Discoverable Credentials): The private key, username, and Relying Party ID are written directly into physical hardware flash memory so that the user can sign in without typing their username first.

Hardware Storage Capacities

Hardware DeviceFirmware VersionResident Key Slot Limit
YubiKey 5 Series$< 5.7.0$25 passkeys
YubiKey 5 Series$\ge 5.7.0$100 passkeys
YubiKey BioAll25 passkeys
Google Titan Key2023+ Edition250 passkeys
Feitian ePass K9/K40Standard32 passkeys

Because Account Abstraction smart wallets require user-less authentication (the user taps their hardware key to retrieve their smart contract account), dApps specify:

{
  "authenticatorSelection": {
    "residentKey": "required",
    "requireResidentKey": true,
    "userVerification": "required"
  }
}

Once you reach the 25th credential on older YubiKey firmware, any subsequent navigator.credentials.create() request returns CTAP2_ERR_KEY_STORE_FULL (0x3A).


Step-by-Step Diagnostic & Key Management

Method 1: Inspect & Delete Passkeys via YubiKey Manager (ykman)

The fastest way to diagnose storage saturation is via the open-source Yubico CLI:

# 1. Install ykman (macOS: brew install ykman | Windows: winget install Yubico.YubiKeyManager)
ykman --version

# 2. List all resident FIDO2 credentials (requires FIDO2 PIN)
ykman fido credentials list

Sample Output:

Enter your FIDO2 PIN: ****
Credential ID                                     RP ID               User name
------------------------------------------------  ------------------  ----------------------
3f4a1c2e8b...                                     coinbase.com        0x9B2...7A1
a7c8d9e0f1...                                     layerzerofault.site victor.vance
... (25 total entries)

To free up slots for your Web3 smart wallet:

# Delete a specific obsolete credential using its Credential ID
ykman fido credentials delete <CREDENTIAL_ID>

Method 2: Manage Passkeys via Windows 11 Settings

Windows 11 includes a native passkey management dashboard for external security keys:

  1. Open Windows Settings $\to$ Accounts $\to$ Passkeys.
  2. Scroll to Security Key Settings and click Manage.
  3. Insert your hardware key into the USB port and enter your Security Key PIN.
  4. Review the list of stored credentials and remove old, deprecated dApp test credentials.

Developer Defense: Graceful Fallback Handling in Web3 dApps

When writing client-side WebAuthn onboarding code with @simplewebauthn/browser or Wagmi / Viem passkey connectors, never let OperationError or 0x3A fail silently.

Catch the error and prompt the user with clear hardware-capacity instructions:

// passkey-registration-guard.ts
import { startRegistration } from '@simplewebauthn/browser';
import type { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types';

export async function registerPasskeyWithStorageCheck(
  options: PublicKeyCredentialCreationOptionsJSON
) {
  try {
    const credential = await startRegistration({ optionsJSON: options });
    return credential;
  } catch (error: any) {
    // Detect FIDO2 hardware storage overflow
    const errorMessage = error?.message || '';
    const isStorageFull =
      errorMessage.includes('OperationError') ||
      errorMessage.includes('0x3A') ||
      errorMessage.includes('KEY_STORE_FULL') ||
      (error.name === 'NotAllowedError' && errorMessage.includes('unknown reason'));

    if (isStorageFull) {
      throw new Error(
        'Hardware Security Key Full: Your device (YubiKey/Titan) has reached its maximum resident key limit (25–100 credentials). Please delete unused passkeys using YubiKey Manager or use a platform passkey (Windows Hello / Touch ID).'
      );
    }

    throw error;
  }
}

Best Practice Architecture: Use residentKey: "preferred"

If your smart contract architecture can accept an address or username during the initial lookup phase, change residentKey from "required" to "preferred":

// Config that allows non-resident fallback when hardware key is full
const options = {
  authenticatorSelection: {
    authenticatorAttachment: 'cross-platform',
    residentKey: 'preferred', // Allows non-resident key creation if storage is full!
    requireResidentKey: false,
    userVerification: 'preferred',
  },
};

This configuration permits the hardware key to fall back to generating a non-resident key wrapped inside the credentialId, completely bypassing physical NVRAM slot exhaustion.

[!TIP] Diagnostic Verification & Air-Gapped Testing: Before executing state changes or broad recovery steps, cross-reference failure parameters with our companion guide on Why Windows 11 Device-Bound Passkeys Cannot Be Exported (Alternatives) and verify transaction calldata or cryptographic envelopes using the WebAuthn & Passkey Enclave Diagnostics Debugger.

Interactive Diagnostic Sandbox

Local WebAuthn & Smart Account Sandboxes

Debug WebAuthn credential requests, PRF extensions, and simulate ERC-4337 passkey account validation in client WebCrypto.

Companion Diagnostic Guide Windows Hello Passkeys in TPM 2.0: Non-Exportable Private Key & Enclave Lock Fix →

How Windows Hello stores non-exportable passkey private keys in your TPM 2.0 platform authenticator—plus how to fix TPM lockouts and NotAllowedError safely.

Read Guide
Contextual Architecture

Related Diagnostic Guides

View All in Silo →

Related Inquiries

Why does navigator.credentials.create() fail with OperationError when using a hardware security key?

Hardware security keys such as YubiKey 5 Series have hardware NVRAM limits for FIDO2 Resident Keys (Discoverable Credentials) — typically 25 to 100 credentials. When smart accounts request residentKey: 'required' and the key's onboard memory is full, the device returns CTAP2 error 0x3A (CTAP2_ERR_KEY_STORE_FULL), which the browser surfaces as DOMException: OperationError or NotAllowedError.

How can I check how many passkeys are stored on my YubiKey?

Use the official YubiKey Manager CLI (ykman). Run 'ykman fido credentials list' in your terminal. It will prompt for your FIDO2 PIN and output all resident credentials grouped by Relying Party ID (rpId) along with remaining capacity.

How should Web3 dApps configure WebAuthn registration to avoid hardware memory limits?

In the PublicKeyCredentialCreationOptions payload, set authenticatorSelection.residentKey to 'preferred' rather than 'required' when discoverable credentials are not strictly necessary, or allow users to supply an existing credentialId for server-side lookup.