Esta página se tradujo automáticamente. Lee la versión original en inglés aquí.
En producción, los errores de WebAuthn son confusos porque los navegadores exponen un pequeño conjunto de nombres de DOMException (como NotAllowedError) que pueden representar múltiples causas subyacentes. Además, la gran mayoría de los "errores" (a menudo por encima del 95 % en implementaciones optimizadas a gran escala) son en realidad comportamiento esperado (el usuario canceló el mensaje de clave de acceso del sistema operativo).
Experimenta con flujos de passkeys en Passkeys Debugger.
Importante: Por razones de privacidad, los navegadores no distinguen si el usuario canceló activamente o si no existía ninguna clave de acceso. Sin embargo, en algunas situaciones y con suficiente contexto, tanto en la web como en plataformas nativas, algunos de estos casos se pueden diferenciar utilizando señales como el tiempo.
Si desea las definiciones canónicas para estos nombres, comience con DOMException en MDN. Para las condiciones específicas de WebAuthn que conducen a estas excepciones (y lo que los navegadores están obligados a aplicar), consulte la especificación de Web Authentication del W3C.
Si trata todos los errores como "errores del sistema", hará las cosas mal:
NotAllowedError.En este artículo respondemos a lo siguiente:
NotAllowedError en grupos procesables (cancelación vs. tiempo de espera vs. disponibilidad)?Artículos recientes
⚙️
Hoja de trucos de claves de acceso para desarrolladores
👤
Cómo eliminar una clave de acceso en Apple, Windows y Android
📖
Guía definitiva sobre errores de WebAuthn en producción (2026)
📖
Explicación técnica de la Conditional UI de WebAuthn (autocompletar claves de acceso)
📖
Claves de acceso en el navegador Brave (2026): Qué funciona y qué falla
NotAllowedError es una señal de superficie, no una causa raíz. Puede significar cancelación, tiempo de espera, "sin credencial local" o falta de activación del usuario según el contexto.NotAllowedError significa cosas diferentes durante el inicio de sesión de la interfaz de usuario condicional, el inicio de sesión modal, la creación manual de claves de acceso, la creación condicional y las adiciones activadas automáticamente.<1s), cancelación por parte del usuario (1-15 s) y tiempo de espera (30 s+) son categorías fundamentalmente diferentes.AbortError suele ser un problema de ciclo de vida/concurrencia (navegación, re-renderizado, múltiples solicitudes en curso).SecurityError casi siempre es un problema de configuración/contexto y es raro en implementaciones de producción maduras.error.name para que pueda clasificar los errores en grupos que realmente pueda solucionar.Si solo necesita una asignación rápida para desbloquear la depuración, comience con esta tabla. Está sesgada hacia lo que los equipos realmente ven en los paneles y en los tickets de soporte.
error.name | Lo que normalmente significa en producción | Qué comprobar para confirmar | Primera acción (UX + ingeniería) |
|---|---|---|---|
NotAllowedError | El usuario descartó la hoja, se agotó el tiempo de espera o la falta de disponibilidad se colapsó en un grupo. Este es el mayor grupo de errores en producción. | Tiempo hasta el error, si apareció la interfaz de usuario de código QR/híbrida, si la ceremonia comenzó a partir de una acción real del usuario | Tratar como se esperaba: restaurar la interfaz de usuario + mostrar una alternativa |
AbortError | Su aplicación (o el navegador) abortó la ceremonia | Navegación/re-renderizado durante la ceremonia; llamadas WebAuthn concurrentes; AbortController.abort() | Imponer una sola solicitud en curso; evitar cambios de ruta; manejar la interrupción como un flujo de control normal |
SecurityError | Contexto/política no permitidos | Estrategia de origen + ID de RP; iframe/incrustación; HTTPS; política de características | Arreglar la configuración de ID de RP/origen; validar las políticas de incrustación; garantizar un contexto seguro |
InvalidStateError | Falta de coincidencia de estado (a menudo registro duplicado) | Registro frente a inicio de sesión; excludeCredentials; credencial existente en el autenticador | Tratar como "ya inscrito"; ajustar la ruta de UX; arreglar la generación de opciones |
ConstraintError | No se pueden satisfacer los requisitos | Requisitos de authenticatorAttachment, userVerification, clave residente | Relajar las restricciones o proporcionar una ruta/alternativa alternativa. Ejemplo: falta el bloqueo de pantalla en Android |
DataError | Las entradas están mal formadas/inconsistentes | Codificación base64url; formatos de id/desafío/identificador de usuario | Arreglar la codificación/serialización; añadir validación en la generación de opciones |
NotSupportedError | La plataforma/navegador no es compatible con lo que solicitó | Versión del sistema operativo/navegador; suposiciones de detección de características | Recurrir inmediatamente a una alternativa; registrar el segmento; evitar mostrar llamadas a la acción (CTA) de claves de acceso para entornos no compatibles |
UnknownError | La plataforma/autenticador falló de forma genérica | Picos después de actualizaciones del sistema operativo; compilación del dispositivo; problemas con el proveedor de credential-manager | UX compatible con reintentos; capturar números de compilación; investigar picos en los segmentos |
Una cosa que es fácil pasar por alto: el mismo error.name puede significar cosas muy diferentes dependiendo del tipo de operación. Tenga en cuenta el contexto de la operación al leer las siguientes secciones. En la práctica, los errores de creación de claves de acceso (registro) generalmente superan en número a los errores de inicio de sesión por un amplio margen: la tabla anterior se aplica a ambos, pero la creación es donde reside la mayor parte del volumen.
A continuación, profundizaremos en NotAllowedError porque es el que verá con más frecuencia y el que los equipos interpretan mal con mayor frecuencia.
NotAllowedError a menudo parece "fallaron las claves de acceso", pero normalmente es la plataforma diciéndole que el usuario no completó la interfaz de usuario del sistema operativo. La clave es dividirlo en grupos sobre los que pueda actuar.
Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Chrome, Edge | NotAllowedError: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client. |
| Safari, WebKit | NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. |
| Safari, WebKit | NotAllowedError: This request has been cancelled by the user. |
| Chrome, Edge | NotAllowedError: The operation is not allowed at this time because the page does not have focus. |
| Safari, WebKit | NotAllowedError: The document is not focused. |
| Firefox | NotAllowedError: Operation failed. |
Todos estos se manifiestan como error.name === "NotAllowedError". El error.message difiere según el motor del navegador y la causa subyacente, pero el resultado es el mismo: la ceremonia no se completó.
Esto se aplica tanto al inicio de sesión como a la creación de claves de acceso. Durante el inicio de sesión (interfaz de usuario condicional, modal con o sin lista de permitidos), NotAllowedError suele significar que el usuario no completó la ceremonia. Durante la creación de claves de acceso, el mismo error surge por diferentes razones: el usuario descartó el cuadro de diálogo de creación (la creación condicional no funcionó, o la página perdió el foco durante una adición activada automáticamente). El tipo de operación cambia lo que significa el error y lo que debe hacer al respecto.
El tiempo a menudo es una señal subestimada. Un error después de menos de un segundo de un clic suele ser un rechazo inmediato (el entorno no puede hacerlo, el documento no está enfocado, falta de capacidad). Un error después de unos segundos es una cancelación del usuario (vieron el cuadro de diálogo y decidieron no continuar). Un error después de 30 o más segundos es un tiempo de espera. En las plataformas nativas, el tiempo es especialmente importante: los viajes de ida y vuelta del autenticador, las indicaciones biométricas y las transferencias del administrador de credenciales tienen duraciones características que le ayudan a separar "no funcionó" de "el usuario se alejó". Aún así, no puede distinguir fácilmente si existía una clave de acceso.
No necesita una señal perfecta. Necesita suficiente contexto para evitar tratar cada NotAllowedError de la misma manera. A iOS/Safari se le presta especial atención a continuación porque tiene restricciones únicas (requisitos de activación del usuario en versiones anteriores), pero en el volumen de errores sin procesar, Windows y los navegadores Chromium a menudo generan más NotAllowedError que cualquier otra plataforma. Estas señales a menudo le llevan al 80 % del camino:
| Señal | Significado probable | Qué hacer a continuación |
|---|---|---|
Fallo inmediato (<1s) | Rechazo del entorno: sin capacidad, el documento no está enfocado, la superficie de creación condicional no está disponible | Comprobar la detección de características; asegurarse de que el documento tiene el foco; verificar que la operación es compatible en esta plataforma |
| Cancelación rápida (1-3 s) | Solicitud sorpresiva / sin contexto | Cambiar el tiempo de la solicitud; agregar un tiempo de espera después de la cancelación |
| Cancelación de duración del usuario (3-15 s) | El usuario vio el cuadro de diálogo y decidió no continuar | UX esperada; restaurar la interfaz de usuario + mostrar una alternativa |
| Tiempo de espera (30 s+) | Se agotó el tiempo de espera de la ceremonia sin acción del usuario | Agrupar como "no se completó"; considerar si la solicitud fue notada |
| Aparece la interfaz de usuario de código QR/híbrida antes del fallo | No hay ninguna credencial local disponible en este dispositivo. Nota: detectar de forma fiable las decisiones de los códigos QR antes de que se produzcan requiere una capa de inteligencia de claves de acceso que sepa si existe una credencial utilizable en el dispositivo actual. | Limitar las ofertas de claves de acceso; hacer explícito "Usar teléfono"; reducir las sorpresas con códigos QR |
| Concentrado en iOS/Safari y activado sin un clic/toque | Falta de activación del usuario | Iniciar la ceremonia a partir de un gesto real del usuario |
| Durante la creación condicional o la adición activada automáticamente | Autocompletar no disponible, la credencial ya existe o la página perdió el foco. Los errores de creación condicional pueden aparecer repentinamente y en gran volumen cuando se lanza la característica, convirtiendo esto en una de las mayores fuentes de errores de la noche a la mañana. | Ver la creación condicional; comprobar el estado de visibilidad del documento; utilizar getClientCapabilities() para verificar la compatibilidad con conditionalCreate antes de intentar la llamada |
Esta es también la razón por la que NotAllowedError rara vez debería ser visible para el usuario. No es un mensaje sobre el que el usuario pueda actuar.
La clasificación por contexto es también donde las tasas de éxito se dividen más marcadamente. El análisis de la tasa de éxito de la autenticación de claves de acceso del Corbado Passkey Benchmark 2026 mide la finalización del primer trimestre de 2026 entre el 55 y el 95 % para los flujos centrados en el identificador en dispositivos desconocidos, frente al 95-99 % para los retornos en dispositivos conocidos en implementaciones B2C a gran escala. El primer identificador web de iOS alcanza el 85-95 % de finalización (% CDA 0-5 %), el web de Android el 70-85 % (% CDA 5-10 %) y el web de macOS el 70-85 % (% CDA 10-15 %), mientras que el web de Windows se sitúa en un 45-60 % de finalización del primer identificador con un % CDA en 55-65 % en Windows 11 y 40-55 % en Windows 10. Leer el volumen de NotAllowedError sin separar los contextos de dispositivos conocidos y desconocidos confunde dos regímenes de éxito fundamentalmente diferentes.
Un matiz que importa en producción: algunos agentes de usuario pueden mostrar los tiempos de espera como TimeoutError, pero muchos equipos todavía ven que los tiempos de espera se colapsan en NotAllowedError en los paneles. De cualquier manera, trate los tiempos de espera como "la ceremonia no se completó" y agrúpelos usando el tiempo más el contexto.
Cuando se descarta la hoja del sistema operativo o se agota el tiempo de espera, su interfaz de usuario debería recuperarse inmediatamente y reaccionar con gracia. Un conjunto práctico de reglas:
Más allá de lo básico:
Si sus "cancelaciones" son realmente altas, el siguiente paso es solucionar las causas fundamentales subyacentes: tiempo de solicitud, sorpresas de códigos QR y baja disponibilidad.
Comience con los cambios que mueven las métricas rápidamente:
NotAllowedError. Comience con isUVPAA() como la puerta más básica, luego use getClientCapabilities() para comprobaciones más precisas (creación condicional, obtención condicional, transporte híbrido, autenticador de plataforma). Tenga en cuenta que las API de detección pueden romperse con las actualizaciones del sistema operativo: iOS 26.2 envió un error de WebKit donde isUVPAA() devuelve false en todos los navegadores basados en WKWebView a pesar de que las claves de acceso funcionan bien, causando picos repentinos de NotAllowedError para el 10-25 % de los usuarios de iOS.Los nombres de error son un objetivo en movimiento. Hay propuestas en curso para agregar errores WebAuthn más granulares (por ejemplo, para separar "no hay credencial disponible" de "usuario cancelado"). A partir de febrero de 2026, esto no está implementado en ningún navegador, por lo que todavía vale la pena construir sus propios grupos de razones según el contexto y el tiempo. Si desea realizar un seguimiento de este trabajo, consulte el problema #2062 de WebAuthn y la explicación sobre los "Nuevos códigos de error".
Los nombres de error restantes son menos frecuentes pero aún vale la pena entenderlos cuando aparecen.
AbortError es poco común en volumen en comparación con NotAllowedError, pero cuando aparece es altamente diagnóstico: por lo general, significa que la ceremonia no terminó porque su aplicación invalidó la solicitud: ocurrió una navegación, cambió el estado o comenzó una segunda solicitud.
Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Chrome, Edge | AbortError: The operation was aborted. |
| Chrome, Edge | AbortError: Aborted by AbortSignal. |
| Firefox | AbortError: signal is aborted without reason |
| Firefox | AbortError: Operation timed out. |
| Safari, WebKit | AbortError: The user aborted a request. |
| Chrome | AbortError: CredentialContainer request is not allowed. |
Las causas comunes de producción incluyen:
AbortController.abort() durante reintentos o limpieza de estado.Para solucionarlo, céntrese en hacer de la ceremonia una "sección crítica":
Si ve que AbortError se concentra en superficies incrustadas o aplicaciones multidominio, el siguiente grupo que debe verificar es SecurityError.
SecurityError es el navegador diciéndole: "a este contexto no se le permite hacer lo que pidió". En la práctica es casi siempre de configuración, no comportamiento del usuario. En las implementaciones maduras de producción, SecurityError es raro porque estos problemas normalmente se detectan durante las pruebas de integración. Si aparece en producción, por lo general significa que se agregó un nuevo dominio, contexto de incrustación o destino de implementación sin la configuración adecuada de WebAuthn.
Las causas comunes incluyen:
.well-known/webauthn o .well-known/assetlinks.json mal configurados, faltantes o no disponibles temporalmente. Los problemas de red durante la ventana crítica cuando el navegador obtiene estos archivos causarán fallos. Un punto ciego común: si su página de inicio está inactiva por mantenimiento, los archivos "well-known" también están fuera de línea, rompiendo las ceremonias de claves de acceso en todas las partes que confían (relying parties) y que dependen de ellos.Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Chrome, Edge | SecurityError: WebAuthn is not supported on sites with TLS certificate errors. |
| Cualquier navegador | SecurityError: The relying party ID is not a registrable domain suffix of, nor equal to the current origin's effective domain. |
| Chrome (iframe) | SecurityError: The 'publickey-credentials-create' feature is not enabled in this document. |
En producción, SecurityError es raro: casi siempre se detectan durante las pruebas de integración. Cuando aparecen, el error en el certificado TLS es el sobreviviente más común.
El ciclo de depuración más rápido es:
publickey-credentials-create / publickey-credentials-get): Permissions-Policy de MDN.Una vez que se ha resuelto SecurityError, el siguiente grupo a tratar seriamente es el conjunto de errores que a menudo indican errores de implementación: InvalidStateError, ConstraintError y DataError.

Hoja de referencia de Passkeys. Guías prácticas, patrones de despliegue y KPIs para programas de passkeys.
Estos errores deberían ser raros en una implementación de claves de acceso madura. Cuando aparecen, generalmente indican que la generación de opciones es incorrecta para un segmento o que el flujo está en un estado incorrecto.
Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Safari, WebKit | InvalidStateError: The user attempted to register an authenticator that contains one of the credentials already registered with the relying party. |
| Chrome, Edge | InvalidStateError: At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator. |
| Chrome, Edge | InvalidStateError: A request is already pending. |
| Firefox | InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable |
Significados típicos:
Manejo práctico:
excludeCredentials enumera todos los identificadores de credenciales existentes para el usuario, de modo que el autenticador pueda detectar los duplicados.InvalidStateError es esperado y debe ser ignorado silenciosamente: significa que ya existe una clave de acceso en el proveedor. Lo mismo se aplica a NotAllowedError y AbortError durante la creación condicional (consulte creación condicional en Chrome).Significado típico: el autenticador no puede satisfacer las restricciones solicitadas.
Desencadenantes comunes:
authenticatorAttachment o la clave residente.userVerification en segmentos donde no están disponibles.Arreglo: relaje las restricciones (cuando sea aceptable) o proporcione una ruta alternativa. Para el caso en el que falta el bloqueo de la pantalla, considere detectar esta condición y guiar a los usuarios en lugar de fallar silenciosamente (Android).
Significado típico: las entradas están mal formadas o son inconsistentes.
Desencadenantes comunes:
Arreglo: valide y normalice las entradas en el límite donde genera las opciones de WebAuthn. En la práctica, DataError está efectivamente ausente en los sistemas de producción maduros: si su generación de opciones está probada, no lo verá en los paneles.
Si estos errores están bajo control, la siguiente pregunta es la cobertura: ¿están fallando los usuarios porque el entorno no puede hacer WebAuthn de la forma que usted espera?
NotSupportedError es una señal de cobertura, no una señal de fiabilidad. Suele significar que un segmento no puede hacer lo que usted pidió (sistema operativo/navegador demasiado antiguo, falta capacidad, característica no habilitada).
Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Chrome, Edge | NotSupportedError: The user agent does not support public key credentials. |
| Firefox | NotSupportedError: Resident credentials or empty 'allowCredentials' lists are not supported. |
| Chrome, Edge, Firefox | TypeError: PublicKeyCredential.parseCreationOptionsFromJSON is not a function |
| Chrome, Edge, Firefox | TypeError: PublicKeyCredential.parseRequestOptionsFromJSON is not a function |
| Chrome, Edge, Firefox | TypeError: credential.toJSON is not a function |
| Safari | TypeError: Can only call PublicKeyCredential.toJSON on instances of PublicKeyCredential |
Los dos primeros son DOMException genuinos de tipo NotSupportedError. Las entradas TypeError son técnicamente un tipo de excepción diferente, pero representan la misma clase de problema: el navegador o el entorno no admiten lo que pidió. La familia de TypeError de serialización JSON es mucho más común en la práctica que el propio NotSupportedError DOMException (consulte a continuación).
Las causas comunes incluyen:
La familia de serialización JSON es la mayor fuente de fallos de la clase NotSupportedError en producción. Técnicamente, estos aparecen como TypeError (falta el método), no como una DOMException, pero aquí es donde los encontrará. Dos causas subyacentes distintas:
navigator.credentials pero no PublicKeyCredential.parseCreationOptionsFromJSON / parseRequestOptionsFromJSON. Esto representa aproximadamente el 90 % de esta familia de errores, concentrada en versiones antiguas de Safari y Chrome. Si su biblioteca de cliente depende de estos métodos sin una alternativa, esto produce un volumen de error significativo..toJSON(). Las extensiones como Bitwarden, LastPass o 1Password pueden interceptar la ceremonia y devolver un objeto que parece una credencial pero no es una instancia real de PublicKeyCredential. Llamar a .toJSON() en ella lanza una excepción, devuelve un valor no definido, o el objeto es null por completo. Esto es aproximadamente el 10 % de la familia, pero es especialmente confuso para la depuración porque los mensajes de error difieren según el navegador (Safari: "Can only call on instances of PublicKeyCredential"; Firefox: "does not implement interface PublicKeyCredential").El manejo debe ser contundente y rápido:
Si la cobertura parece estar bien pero los fallos siguen ocurriendo en segmentos específicos, es posible que se trate de problemas de la capa de plataforma expuestos como UnknownError.
UnknownError es un cajón de sastre para los fallos del autenticador/sistema operativo que no encajan claramente en las demás categorías. A menudo es transitorio, pero también puede tener picos después de las actualizaciones del sistema operativo.
Lo que verá en la consola del navegador:
| Fuente | Mensaje de error |
|---|---|
| Chrome (Android) | UnknownError: An unknown error occurred while talking to the credential manager. |
| Cualquier navegador | UnknownError: The operation failed for an unknown transient reason. |
| Cualquier navegador | UnknownError: Either the device has received unexpected request data, or the device has been reconfigured since the request was made. |
| Cualquier navegador | UnknownError: Something went wrong. |
| Chrome (LastPass) | TypeError: Cannot use 'in' operator to search for 'type' in null |
| Safari (LastPass) | TypeError: null is not an Object. (evaluating 'key in input') |
| Chrome (Bitwarden) | FallbackRequested |
Manejo práctico:
Una fuente especializada de errores que no encaja claramente en ninguna categoría de DOMException: las extensiones de navegador de los administradores de contraseñas (como Bitwarden, LastPass, 1Password y otras) pueden interceptar las llamadas a la API de WebAuthn y devolver respuestas no estándar. Si bien el volumen es pequeño en comparación con las cancelaciones de los usuarios, vale la pena realizar un seguimiento porque afectan a segmentos de usuarios específicos de manera constante y los síntomas son confusos: faltan métodos en el objeto de credencial devuelto, tipos de error inesperados o respuestas mal formadas que no coinciden con ningún error documentado de WebAuthn. Estos a menudo surgen como UnknownError o como excepciones no clasificadas. Si ve picos de errores concentrados en navegadores específicos sin una explicación a nivel del sistema operativo, compruebe si hay implicada una extensión de un administrador de credenciales.
Hasta ahora hemos cubierto los nombres de errores en el navegador web. Pero si también envía aplicaciones nativas, el panorama de errores es diferente, y en cierto modo, significativamente mejor.
Todo lo anterior abarca los navegadores web. Las aplicaciones nativas (iOS con el framework ASAuthorization, Android con Credential Manager) comparten las mismas categorías de error fundamentales pero difieren de formas importantes:
"Sin credenciales" es una señal clara. En la web, los navegadores agrupan "no hay credencial disponible" y "el usuario canceló" en el mismo NotAllowedError por razones de privacidad. De forma nativa, usar preferImmediatelyAvailableCredentials en iOS (ASAuthorizationController) o setPreferImmediatelyAvailableCredentials(true) en Android (GetCredentialRequest) le indica al sistema operativo que solo presente las credenciales que ya se encuentran en el dispositivo y que falle inmediatamente si no existe ninguna. Esto le brinda una señal limpia de "no hay credenciales" que la web no puede proporcionar.
El estado del proveedor de credenciales es visible. Las plataformas nativas, bajo algunas condiciones, pueden decirle cuándo no hay ningún proveedor de credenciales (Google Password Manager, iCloud Keychain, 1Password, etc.) instalado, configurado o establecido como predeterminado y reaccionar ante ello. En la web, esta información está oculta detrás de mensajes opacos de NotAllowedError.
Los mensajes de error son más específicos. Debido a que el usuario ha instalado la aplicación, y por lo tanto, ha establecido una relación de confianza con la parte que confía (relying party), el sistema operativo muestra más detalles de diagnóstico. Las consideraciones de privacidad que obligan a los navegadores web a ser vagos no se aplican de la misma manera cuando la aplicación ya está en el dispositivo. iOS devuelve mensajes localizados en el idioma del dispositivo del usuario. Android devuelve tipos de error estructurados con cadenas de causa. Esto facilita la depuración, pero significa que su manejo de errores debe tener en cuenta la localización y los formatos de error específicos de la plataforma.
iOS muestra los errores de las claves de acceso a través del framework ASAuthorization. Todos los errores llegan en el callback de delegado authorizationController(controller:didCompleteWithError:) como objetos NSError.
Clasificar por dominio + código, no por la cadena de mensajes. El dominio de error primario es com.apple.AuthenticationServices.AuthorizationError (ASAuthorizationError.errorDomain). Transforme el error con let nsError = error as NSError y haga coincidir con .domain y .code. Nunca haga coincidir con .localizedDescription en producción: los mensajes de Apple están localizados en más de 30 idiomas y pueden cambiar en las distintas versiones del sistema operativo. Las cadenas de mensaje que se enumeran a continuación son útiles para reconocer los errores en los registros, pero no son criterios de clasificación.
Códigos públicos ASAuthorizationError:
| Código | Nombre | Desde | Significado |
|---|---|---|---|
| 1000 | Unknown | iOS 13 | No debería aparecer en producción. Cajón de sastre genérico. |
| 1001 | Canceled | iOS 13 | El usuario descartó la hoja de clave de acceso. Es el error más común en general: el equivalente a NotAllowedError. Señal limpia con un userInfo vacío y sin ningún error subyacente. |
| 1002 | InvalidResponse | iOS 13 | Corrupción a nivel de framework. Raro en la práctica. |
| 1003 | NotHandled | iOS 13 | Ningún proveedor manejó la solicitud. Verifique los derechos y la configuración del proveedor de credenciales. |
| 1004 | Failed | iOS 13 | Fallo genérico. El localizedDescription contiene la verdadera razón (por ejemplo, "Application with identifier X is not associated with domain Y"). userInfo puede contener una cadena de FailureReason, pero NSUnderlyingErrorKey no siempre está relleno: los fallos de asociación de dominio devuelven nil para el error subyacente. |
| 1005 | NotInteractive | iOS 15 | No hay credenciales disponibles cuando se usa preferImmediatelyAvailableCredentials. Esta es la señal limpia de "no encontrado": el equivalente en iOS a "no existe ninguna clave de acceso en este dispositivo". No se mostró ninguna interfaz de usuario. |
| 1006 | MatchedExcludedCredential | iOS 18 | Ya existe una clave de acceso para este RP en este dispositivo. Señal limpia para la detección de duplicados: userInfo vacío, no hay NSUnderlyingErrorKey. La clasificación funciona sin emparejamiento de cadenas. |
| 1007 | CredentialImport | iOS 18.2 | Falló la importación de credenciales. |
| 1008 | CredentialExport | iOS 18.2 | Falló la exportación de credenciales. |
| 1009 | PreferSignInWithApple | iOS 26 | El usuario prefiere Sign in with Apple en lugar de la clave de acceso. Nuevo en iOS 26. |
| 1010 | DeviceNotConfiguredForPasskeyCreation | iOS 26 | El dispositivo no tiene un código de acceso o la configuración de iCloud Keychain. Error conocido en el simulador de iOS 26: devuelve 1010 incluso cuando la configuración es correcta (no se reproduce en dispositivos físicos). |
La distinción más importante para la producción: desde iOS 18, las credenciales duplicadas devuelven su propio código de error 1006 (MatchedExcludedCredential). En iOS 17 y versiones anteriores, las credenciales duplicadas estaban ocultas dentro del código 1004 (Failed). En iOS 18+, la distinción es estructural (diferente código de error), no textual.
Errores comunes en tiempo de ejecución (referencia a nivel de registro):
Estos mensajes aparecen en localizedDescription o en userInfo para casos específicos de fallos. Úselos para búsquedas en los registros y la depuración, no para la clasificación programática.
| Mensaje (configuración local en inglés) | Código subyacente | Notas |
|---|---|---|
Application with identifier <TeamID.BundleID> is not associated with domain X | 1004 (Failed) | El derecho de Dominios Asociados de la aplicación no coincide con el de la parte que confía (relying party). Arregle el archivo apple-app-site-association en su servidor. |
Couldn't communicate with a helper application. | 1004 (Failed) | La extensión del proveedor de credenciales no respondió. Transitorio: es apropiado reintentarlo. |
Request already in progress for specified application identifier. | 1004 (Failed) | Se envió una solicitud duplicada de ASAuthorization mientras había una pendiente. Condición de carrera (race condition) en la aplicación. |
Stolen Device Protection is enabled and biometry is required. | 1004 (Failed) | Stolen Device Protection de iOS 17+ bloquea la autenticación biométrica en ubicaciones desconocidas. Los desarrolladores no pueden actuar sobre esto, pero vale la pena mostrarlo al usuario. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 2.) | Dominio separado | El intercambio (handshake) por Bluetooth para la autenticación entre dispositivos (híbrido/CABLE) ha fallado. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 3.) | Dominio separado | La conexión por Bluetooth para la autenticación entre dispositivos ha fallado. |
Mensajes localizados de "sin credenciales" (código 1005):
Cuando se establece preferImmediatelyAvailableCredentials y no existe ninguna clave de acceso, iOS devuelve el código 1005 (NotInteractive) con un mensaje localizado en el idioma del dispositivo del usuario. Esto es exclusivo de las aplicaciones nativas: los navegadores web nunca exponen esta señal. El mensaje siempre comienza con The operation couldn't be completed. seguido por el texto localizado:
| Idioma | Mensaje |
|---|---|
| Chino (simplificado) | 没有可用于登录的凭证。 |
| Vietnamita | Không có sẵn thông tin để đăng nhập. |
| Árabe | لا تتوفر بيانات اعتماد لتسجيل الدخول. |
| Español | No hay ninguna credencial disponible para iniciar sesión. |
| Chino (tradicional) | 沒有可用於登入的憑證。 |
| Coreano | 로그인을 위한 자격 증명이 없습니다. |
| Francés (Canadá) | Aucun identifiant disponible pour la connexion. |
| Portugués (Brasil) | Nenhuma credencial disponível para login. |
| Francés (Francia) | Aucune information d'identification n'est disponible pour procéder à la connexion. |
| Tailandés | ไม่มีข้อมูลประจำตัวสำหรับเข้าสู่ระบบ |
| Italiano | Non ci sono credenziali disponibili per l'accesso. |
| Holandés | Geen inloggegevens beschikbaar. |
| Japonés | ログイン用の資格情報がありません。 |
| Turco | Oturum açmak için kullanılabilecek kimlik bilgisi yok. |
Los dispositivos con configuración regional en inglés (English-locale devices) por lo general resuelven el escenario "sin credenciales" en el nivel de API antes de que el framework ASAuthorization devuelva un error localizado, por lo cual no aparece ninguna variante en inglés en la lista anterior. Programáticamente, siempre verifique la coincidencia con el código 1005 en lugar de analizar gramaticalmente estas cadenas.
Android expone los errores de claves de acceso a través de la API Credential Manager (androidx.credentials). Los mensajes de error incluyen un mensaje primario y a menudo una causa (cause) con detalles adicionales. A diferencia de iOS, Android proporciona tipos de error más estructurados y causas más explícitas para los problemas de configuración.
Cancelación del usuario y detección de credenciales:
| Error | Notas |
|---|---|
User cancelled the operation | El usuario descartó el mensaje de solicitud de clave de acceso. Es el equivalente a NotAllowedError. Nota: Credential Manager también devuelve User canceled the request (con ortografía de EE. UU.) desde una ruta de código diferente: ambas son idénticas. |
Excluded credential matches existing credential | Ya existe una clave de acceso para este ID de credencial. Es el equivalente a InvalidStateError. A diferencia de iOS, el mensaje es diferente al de la cancelación del usuario. |
No create options available. | Ningún proveedor de credenciales elegible puede manejar la solicitud de creación. Normalmente significa que Google Play Services está desactualizado o que ningún proveedor de credenciales admite la creación de claves de acceso. |
Errores de configuración y de seguridad:
| Error | Notas |
|---|---|
Passkeys not supported for this app | Digital Asset Links (assetlinks.json) falta o no contiene la huella dactilar del certificado de firma de la aplicación. Es el equivalente a SecurityError. |
Https failed: respCode=301, url=https://<domain>/.well-known/assetlinks.json | El archivo assetlinks.json devuelve una redirección en lugar de HTTP 200. Android requiere que el archivo esté en la URL exacta y sin redirecciones. |
The incoming request cannot be validated | Credential Manager no puede verificar la solicitud frente a Digital Asset Links. |
RP ID cannot be validated. | El ID de la parte que confía (relying party) en las opciones de WebAuthn no coincide con el de assetlinks.json. |
Screen lock is missing. | No hay ningún PIN, patrón o dato biométrico configurado en el dispositivo. Las claves de acceso requieren la verificación del usuario. Es el equivalente a ConstraintError. |
Cannot find an eligible account. | Ninguna cuenta de Google en el dispositivo es elegible para la creación de claves de acceso (raro, típicamente configuraciones empresariales personalizadas). |
Errores de la plataforma y del autenticador:
| Error | Notas |
|---|---|
Unsuccessful result from folsom activity. | Fallo interno de Google Play Services. "Folsom" es un componente de GMS para las operaciones con claves de acceso. Transitorio: el reintento es apropiado. |
Can't find the proper key to decrypt the private key from WebauthnCredentialSpecifics. | Existe una clave de acceso sincronizada pero el dispositivo no puede descifrar su clave privada. El estado de sincronización de Google Password Manager es inconsistente: la credencial se sincronizó desde otro dispositivo pero la clave de descifrado no está disponible. No es procesable por los desarrolladores. |
Operation was interrupted (causa: The UI was interrupted - please try again.) | La interfaz de usuario (UI) de Credential Manager fue interrumpida por otra actividad (llamada entrante, rotación de la pantalla, aplicación que pasó a segundo plano). Es el equivalente a AbortError. |
Unknown credential error | Cajón de sastre genérico cuando no se aplica ningún tipo de error específico. Suele ser transitorio. |
timeout (causa: Canceled) | La operación de Credential Manager superó el tiempo de espera (timeout) antes de que el usuario completara la verificación biométrica. |
El siguiente diagrama muestra cómo todas las capas analizadas anteriormente (Infraestructura, Entorno, Tipo de operación, Clasificación y Detección) se conectan de un extremo a otro. Es el modelo mental que debe tener en cuenta al diseñar su seguimiento de errores.
La idea clave: un error.name sin procesar solo tiene sentido una vez que se sabe qué capa del Entorno lo produjo, qué Operación se estaba ejecutando y si el error fue Esperado o Inesperado. Las secciones a continuación cubren qué registrar y cómo actuar en consecuencia.
La mayor parte de la clasificación de errores de este artículo puede realizarse únicamente con señales del lado del cliente. Un SDK de observabilidad exclusivamente frontend (frontend-only) captura el contexto suficiente para clasificar la inmensa mayoría de los errores de WebAuthn. Así es también como está diseñado el SDK de observabilidad de Corbado: la capa del lado del cliente se encarga de la atribución de errores, los tiempos, el contexto de las operaciones y la detección de plataformas. El registro (logging) del lado del servidor añade una segunda capa para los fallos que solo el backend puede ver.
El requisito clave: cada intento debe poder unirse de extremo a extremo (end-to-end). Un id de correlación compartido (por ejemplo, auth_flow_id) conecta el contexto del lado del cliente con el resultado de la verificación del servidor.
| Señal | Por qué importa |
|---|---|
error.name + grupo de motivos normalizados | Error del navegador en bruto + su clasificación |
| Tipo de operación | Interfaz de usuario condicional, inicio de sesión modal, creación manual, creación condicional, auto-anexar. CDA (Autenticación cruzada entre dispositivos) es su propia bestia compleja. |
| Contexto del Entorno completo | SO + Versión, Navegador + Versión, Marca/Modelo del hardware, Configuración del autenticador (por ejemplo, ¿GPM habilitado?) |
| Autenticador / contexto del administrador de credenciales | Rotura de extensión y de proveedor |
| Tiempo hasta el error desde el inicio de la operación | Rechazo inmediato (<1s) frente a la cancelación por parte del usuario (1-15s) frente a los tiempos de espera (30s+) |
| Red / Estado de conectividad | Los errores de red se manifiestan a menudo como errores del cliente. Rastrear si el usuario estaba desconectado y poner los registros en cola para enviarlos cuando se restablezca la conectividad. |
| Si apareció el QR/interfaz híbrida | Fallo local vs de dispositivos cruzados |
Id de correlación (auth_flow_id) | Unir con los registros del servidor |
Los errores en la verificación del servidor ocurren después de que el navegador retorna una credencial y un desafío firmado. Deberían ser errores estructurados con códigos explícitos, sin mezclarse en el mismo conjunto que los nombres de DOMException del lado del cliente. Vea: implementación del servidor WebAuthn.
| Señal | Por qué importa |
|---|---|
| Falta de coincidencia de desafío / desafío expirado | Problemas de tiempos o repetición (replay) de sesión |
| Falta de coincidencia de origen / RP ID | Errores de configuración de dominios múltiples |
| Firma inválida / credencial no encontrada | Credencial borrada o corrupta. Caso común: inicio de sesión mediante interfaz condicional con una clave de acceso que el usuario ya borró en el lado del servidor. Utilice la Signal API para mantener las listas de credenciales del cliente y del servidor sincronizadas. |
| Falta de coincidencia del identificador de usuario | Problemas con la asignación de cuentas |
Id de correlación (auth_flow_id) | Unir con el contexto del lado del cliente |
Si desea un modelo de embudo completo (abandonos por paso y conversión entre pasos), consulte: telemetría de claves de acceso para comprender los abandonos.
Suscríbete a nuestro Substack de passkeys para recibir las últimas noticias.
Con estos datos, la conclusión es simple: la mayoría de los “errores” se convierten en correcciones de UX, correcciones de cobertura o correcciones de configuración. Sin embargo, construir y mantener esta clasificación usted mismo es un trabajo continuo significativo.
La lista de comprobación de registros (logging checklist) anterior captura señales en bruto. En producción a escala, error.name por sí solo no es suficiente. Construir esta clasificación uno mismo supone un importante trabajo continuado: los mensajes de error cambian con cada versión del navegador y del sistema operativo, los proveedores de gestores de contraseñas publican actualizaciones que alteran el comportamiento en la ceremonia y las nuevas firmas de errores aparecen con cada lanzamiento de funcionalidades.
error.name no es suficiente por sí solo#El mismo NotAllowedError puede significar seis cosas distintas en función de tres dimensiones que los navegadores no separan por usted:
| Dimensión | Lo que le dan los navegadores | Lo que realmente necesita | Ejemplo |
|---|---|---|---|
| Contexto de la operación | NotAllowedError | ¿Fue una interfaz de usuario condicional, un inicio de sesión modal, una creación manual, una creación condicional o una adición automática? | Android devuelve el mismo "error desconocido" para el descarte de un inicio de sesión (esperado) que para un error en la creación (inesperado). |
| Tiempo | Sin datos de duración | Rechazo inmediato (<1s) frente a cancelación del usuario (1-15s) frente al tiempo de espera (30s+) | 200 ms = rechazo del entorno; 5 s = el usuario vio el cuadro de diálogo y canceló; 35 s = tiempo de espera. |
| Plataforma + autenticador | Un genérico error.name | SO, navegador, versión, administrador de credenciales para cada error | "el usuario cerró el diálogo" en Chrome y "autocompletar no disponible" en Safari, ambos afloran como NotAllowedError |
Este es el problema que el SDK de observabilidad de Corbado fue creado para resolver. Se trata de una integración frontend ligera que se asienta sobre su actual implementación de claves de acceso, trabaja con cualquier servidor WebAuthn y con cualquier IDP, y clasifica cada error de WebAuthn en función de sus tres dimensiones de forma automática:
| Capacidad | Qué hace |
|---|---|
| Atribución de errores | Captura el sistema operativo, la versión del sistema operativo, el navegador, la versión del navegador y el autenticador con cada intento en la ceremonia. |
| Modo de operación | Conecta cada error a la operación específica (interfaz de usuario condicional, inicio de sesión modal, creación manual, creación condicional, adición automática) para que el mismo NotAllowedError se resuelva en causas subyacentes distintas. |
| Tiempos desde el inicio de la acción | Registra la duración desde el inicio de la ceremonia para poder distinguir así los rechazos inmediatos, las cancelaciones de los usuarios y los tiempos de espera (timeouts) sin necesidad de hacer conjeturas. |
| Clasificación inteligente de errores | Busca la coincidencia según el contexto completo del error (y no solo por el nombre), normalizándolo a través de los diversos Entornos (SO, hardware, ajustes). Prioriza grupos de errores diferenciados, como CDA frente al Local, y sabe distinguir los errores Esperados (interrupciones por parte del usuario) de los errores Inesperados (fallo del sistema). |
| Fragmentación de los administradores de contraseñas | Detecta cuándo las extensiones de administradores de credenciales (Bitwarden, 1Password, LastPass) interceptan las ceremonias y retornan unas respuestas no estándares, logrando con ello separar los fallos motivados por las extensiones de los propios fallos de la plataforma. |
Esta es la capa Observe: visibilidad sobre lo que está ocurriendo, sin tener que cambiar su implementación.
La consola de administración de Corbado admite dos vías de investigación:
Top-down (del dashboard a la causa de raíz):
Bottom-up (desde los patrones de error hasta llegar al impacto):
Las dos rutas convergen: de arriba hacia abajo (top-down) te estará diciendo si algo no funciona de forma debida, desde abajo hasta arriba (bottom-up) te revelará su porqué. El AI Analytics Assistant conecta a ambos permitiéndole la realización de las correspondientes consultas en un lenguaje natural en el caso de los datos provenientes de errores, y todo ello lo hará transversalmente frente a aquellas otras métricas empleadas respecto a su adopción.
Los equipos que deseen procesar de un modo proactivo el poder accionar sobre aquellas señales en concreto, pueden pasarse a la fase Adopt, sumando por ello y con ello inteligencia a la clave de acceso de cara al filtrado (a modo de acceso/gate) sobre sus propias ceremonias, o a ser capaz de la optimización que permita unas solicitudes más óptimas en materia de inscripciones a su vez sumado al poder revertir el caso de claves de acceso corrompidas. En el contexto propio al entorno regulado, así como a ese tan particular para todos esos de sus mismos despliegues que operan con características propias del formato híper-escalado, se adicionará al conjunto Enterprise la opción por la de realizar unos hospedajes que dispongan en consecuencia, a su propio inquilino exclusivo (single-tenant), así como de la total integración en cuanto se le precisa hacia todo ese marco en lo del SIEM así mismo conjuntamente al lado por medio de una de aquellas propias por las que se atenga propiamente del total ajustado por ende a la configuración PSD2.
Obtén un whitepaper gratuito de passkeys para empresas.
Los nombres de error de WebAuthn no son un veredicto final. Son pistas, y solo se vuelven accionables cuando los conecta al tipo de operación, el tiempo y el contexto de la plataforma.
NotAllowedError), ciclo de vida/concurrencia de la aplicación (AbortError), configuración/contexto de seguridad (SecurityError), o errores de opción/estado (InvalidStateError, ConstraintError, DataError). La gran mayoría del volumen es NotAllowedError, y la mayor parte de eso es comportamiento esperado (el usuario descartó el aviso).NotAllowedError? Utilice el tiempo (rechazo inmediato frente a la cancelación del usuario frente a tiempo de espera), un indicador de código QR/híbrido (desajuste de disponibilidad), el contexto de activación del usuario (especialmente en iOS/Safari) y el tipo de operación (interfaz de usuario condicional vs inicio de sesión modal vs creación de claves de acceso vs creación condicional). No trate todos los NotAllowedError como el mismo modo de fallo.error.name durante un inicio de sesión de interfaz de usuario condicional es una señal completamente diferente que durante una creación condicional o una creación manual de claves de acceso (el usuario cerró el cuadro de diálogo). Registrar el tipo de operación junto con el error es lo que convierte al genérico NotAllowedError en una categoría accionable.error.name, el tipo de operación, el tiempo de error desde el inicio de la operación, el tipo de flujo, si se mostró la interfaz de usuario de código QR/híbrida, SO/navegador/dispositivo (incluidas las versiones), un id de correlación (auth_flow_id) y rechazos de verificación del servidor como códigos explícitos.Dos reglas empíricas que aplican en todos los tipos de errores: nunca muestre errores nativos del navegador a los usuarios (siempre proporcione una ruta alternativa clara) y separe los intentos locales de los intentos de dispositivos cruzados de código QR/híbrido, ya que fallan por razones diferentes y requieren correcciones diferentes. A escala, mantener la clasificación de errores en navegadores, versiones de sistemas operativos y administradores de credenciales es un trabajo continuo. Considere la posibilidad de utilizar un SDK de observabilidad con una biblioteca de patrones mantenida en lugar de construir esto desde cero.
Corbado es la Authentication Intelligence Platform para equipos de CIAM que gestionan autenticación de consumidores a gran escala. Te ayudamos a ver lo que los logs de tu IDP y las herramientas de analytics genéricas no muestran: qué dispositivos, versiones de SO, navegadores y gestores de credenciales soportan passkeys, por qué los registros no se convierten en inicios de sesión, dónde falla el flujo de WebAuthn y cuándo una actualización de SO o navegador rompe el login en silencio — todo sin reemplazar Okta, Auth0, Ping, Cognito o tu IDP propio. Dos productos: Corbado Observe aporta observabilidad para passkeys y cualquier otro método de login. Corbado Connect añade passkeys gestionados con analytics integrado (junto a tu IDP). VicRoads ejecuta passkeys para más de 5M de usuarios con Corbado (+80 % de activación de passkey). Habla con un experto en Passkeys →
En la web, por motivos de privacidad, los navegadores combinan ambos casos en NotAllowedError, por lo que no se pueden distinguir directamente. Utilice el tiempo como indicador: un error por debajo de 1 segundo normalmente significa un rechazo del entorno o falta de capacidad, mientras que entre 1 y 15 segundos sugiere que el usuario vio y descartó el cuadro de diálogo. En las aplicaciones nativas de iOS y Android, configurar preferImmediatelyAvailableCredentials antes de la solicitud le brinda una señal limpia de "sin credenciales" (código 1005 en iOS, GetCredentialRequest en Android) antes de que se muestre cualquier interfaz de usuario.
En implementaciones optimizadas de claves de acceso a gran escala, más del 95 % de los errores de WebAuthn registrados son abortos esperados de los usuarios, no fallos del sistema. Hacer un seguimiento de los recuentos sin procesar de error.name sin separar "el usuario descartó el aviso" de los fallos genuinos infla las métricas de error y oculta las regresiones reales que se esconden dentro del volumen de NotAllowedError. Divida sus recuentos por tipo de operación y trate las categorías de cancelación del usuario por separado de los errores inesperados como SecurityError, ConstraintError y DataError.
El código 1005 de iOS (NotInteractive) significa que no había ninguna clave de acceso disponible en el dispositivo cuando se estableció preferImmediatelyAvailableCredentials en ASAuthorizationController, y no se le mostró ninguna interfaz de usuario al usuario. Esta es la señal clara de "no existe ninguna clave de acceso en este dispositivo" que los navegadores web no pueden proporcionar debido a las restricciones de privacidad. Clasifique siempre en función del código numérico, no de localizedDescription, porque los mensajes de Apple están localizados en más de 30 idiomas y pueden cambiar en las distintas versiones del sistema operativo.
Durante la creación condicional, NotAllowedError, AbortError e InvalidStateError son resultados esperados y deben ignorarse silenciosamente en lugar de mostrarse como errores. NotAllowedError indica que la función de autocompletar no está disponible o que la página perdió el foco, mientras que InvalidStateError significa que ya existe una clave de acceso en el proveedor. Antes de intentar la llamada, utilice getClientCapabilities() para verificar la compatibilidad con conditionalCreate y compruebe el estado de visibilidad del documento para evitar inflar sus recuentos de errores.
Capture el tipo de operación (interfaz de usuario condicional, inicio de sesión modal, creación manual, creación condicional o adición automática), el tiempo hasta el error desde el inicio de la operación, la versión del sistema operativo, la versión del navegador, el modelo de hardware, si apareció la interfaz de usuario de código QR/híbrida y un identificador de correlación para unirse con los registros del lado del servidor. Los fallos de verificación del servidor, como la falta de coincidencia del desafío, una firma no válida y la credencial no encontrada, deben registrarse como códigos estructurados explícitos, no mezclados en la misma categoría que los nombres de DOMException del lado del cliente. Estas señales juntas permiten clasificar la gran mayoría de los errores en categorías accionables sin tener que adivinar.
Mira cómo Corbado encaja con tu despliegue de passkeys y tu stack de autenticación actual.
Explorar la Console
Artículos relacionados
Tabla de contenidos