---
url: 'https://www.corbado.com/pt/blog/erros-webauthn'
title: 'Guia definitivo sobre erros de WebAuthn em produção (2026)'
description: 'Descubra o que significam erros comuns de WebAuthn como NotAllowedError em produção e como classificá-los por tipo, tempo e contexto.'
lang: 'pt'
author: 'Vincent Delitz'
date: '2026-07-03T07:10:14.593Z'
lastModified: '2026-07-03T07:10:43.578Z'
keywords: 'erros de webauthn, NotAllowedError, AbortError, SecurityError, solução de problemas de WebAuthn, classificação de erros de chaves de acesso, ASAuthorizationError, códigos ASAuthorizationError, androidx.credentials'
category: 'WebAuthn Know-How'
---

# Guia definitivo sobre erros de WebAuthn em produção (2026)

## 1. Introdução

Em produção, os erros de WebAuthn são confusos porque os navegadores expõem um pequeno conjunto de nomes de `DOMException` (como `NotAllowedError`) que podem representar várias causas subjacentes. Além disso, a grande maioria dos "erros" - muitas vezes acima de 95% em implementações otimizadas em grande escala - são, na verdade, **comportamento esperado** (o usuário cancelou o prompt de chave de acesso do sistema operacional).

> Importante: Por motivos de privacidade, os navegadores não distinguem se o usuário cancelou ativamente ou se não existia uma chave de acesso. No entanto, em algumas situações e com contexto suficiente, tanto na web quanto em plataformas nativas, alguns desses casos podem ser diferenciados usando sinais como o tempo de resposta.

Se você quiser as definições canônicas para esses nomes, comece com a documentação do [MDN `DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException). Para condições específicas de WebAuthn que levam a essas exceções (e o que os navegadores são obrigados a aplicar), consulte a [especificação W3C Web Authentication](https://www.w3.org/TR/webauthn-3/).

Se você tratar todos os erros como "bugs", fará as coisas erradas:

- poluirá suas métricas de erro com cancelamentos normais
- perderá regressões reais escondidas na massa de `NotAllowedError`
- enviará interfaces de usuário que confundem os usuários em vez de ajudá-los a se recuperar

Neste artigo, nós respondemos:

- O que os nomes de erros de WebAuthn mais comuns geralmente significam no tráfego real?
- Como você desambigua `NotAllowedError` em categorias acionáveis (cancelamento vs tempo limite vs disponibilidade)?
- Por que o mesmo erro significa coisas diferentes dependendo da operação (login com Conditional UI vs login modal vs criação de chaves de acesso vs criação condicional)?
- Qual contexto mínimo você deve capturar para que "falhou" se torne um problema reproduzível?

## Key Facts

- `NotAllowedError` é um **sinal de superfície**, não uma causa raiz. Pode significar cancelamento, tempo limite, "nenhuma credencial local", ou falta de ativação do usuário dependendo do contexto.
- **O tipo de operação muda o significado.** O mesmo `NotAllowedError` significa coisas diferentes durante o login com Conditional UI, login modal, criação manual de chaves de acesso, criação condicional e adições acionadas automaticamente.
- **O tempo desde o início da operação** é o sinal mais subestimado: imediato (`<1s`), cancelamento pelo usuário (1 a 15s) e tempo limite (30s+) são categorias fundamentalmente diferentes.
- `AbortError` geralmente é um problema de ciclo de vida/concorrência (navegação, re-renderização, múltiplas requisições em andamento).
- `SecurityError` é quase sempre configuração/contexto e raro em implementações maduras em produção.
- "Nomes de erro do navegador" e "rejeições de verificação do servidor" são camadas diferentes. Acompanhe as rejeições do servidor como códigos explícitos, não como falhas genéricas do cliente.
- **Nomes de erro brutos não são acionáveis sozinhos.** Sempre capture o tipo de operação, o tempo e o contexto da plataforma junto com `error.name` para que você possa classificar os erros em categorias que possa realmente corrigir.
- **"Ambiente" é mais do que apenas Navegador + SO.** Para entender verdadeiramente os erros, você precisa rastrear a combinação completa: Versão do SO, Cliente (Versão do Navegador/Aplicativo), configurações do Autenticador (por exemplo, status do iCloud/GPM) e o Modelo de Hardware específico.
- **Falhas de login são P1, Falhas de criação são P2.** Enquanto os erros de criação (P2) frequentemente têm maior volume devido aos abandonos dos usuários, os erros de login (P1) bloqueiam o acesso e exigem alerta imediato.

## 2. Uma folha de referências de produção

Se você precisa apenas de um mapeamento rápido para desbloquear a depuração, comece com esta tabela. Ela é focada no que as equipes realmente veem em painéis e tickets de suporte.

| **`error.name`** | **O que geralmente significa em produção** | **O que verificar para confirmar** | **Primeira ação (UX + engenharia)** |
| --- | --- | --- | --- |
| `NotAllowedError` | Usuário descartou a tela, tempo limite excedido, ou incompatibilidade de disponibilidade agrupados em uma única categoria. Esta é a maior categoria de erro em produção. | tempo até o erro, se a interface QR/híbrida apareceu, se a cerimônia começou a partir de uma ação real do usuário | Tratar como esperado: restaurar UI + mostrar alternativa |
| `AbortError` | Seu aplicativo (ou o navegador) abortou a cerimônia | navegação/re-renderização durante a cerimônia; chamadas WebAuthn concorrentes; `AbortController.abort()` | Forçar uma solicitação em andamento; evitar mudanças de rota; tratar o aborto como fluxo de controle normal |
| `SecurityError` | Contexto/política não permitida | estratégia de ID de RP + origem; iframe/incorporação; HTTPS; feature policy | Corrigir configuração de origem/ID de RP; validar políticas de incorporação; garantir contexto seguro |
| `InvalidStateError` | Incompatibilidade de estado (frequentemente registro duplicado) | registro vs login; `excludeCredentials`; credencial existente no autenticador | Tratar como "já inscrito"; ajustar o caminho da UX; corrigir a geração de opções |
| `ConstraintError` | Requisitos não podem ser satisfeitos | `authenticatorAttachment`, `userVerification`, requisitos de chaves residentes | Relaxar restrições ou fornecer caminho/alternativa. Exemplo: Bloqueio de tela ausente no Android |
| `DataError` | Entradas malformadas/inconsistentes | codificação base64url; formatos de id/desafio/identificador do usuário | Corrigir codificação/serialização; adicionar validação na geração de opções |
| `NotSupportedError` | Plataforma/navegador não suporta o que você pediu | versão do SO/navegador; suposições de detecção de recursos | Recorrer imediatamente a alternativa; registrar segmento; evitar mostrar CTAs de chaves de acesso para ambientes não suportados |
| `UnknownError` | Plataforma/autenticador falhou de maneira genérica | picos após atualizações do SO; build do dispositivo; problemas no provedor de gerenciamento de credenciais | UX amigável para novas tentativas; capturar números de build; investigar picos de segmentos |

Uma coisa fácil de perder: o mesmo `error.name` pode significar coisas muito diferentes dependendo do **tipo de operação**. Tenha em mente o contexto da operação ao ler as seções abaixo. Na prática, os erros de criação de chaves de acesso (registro) normalmente superam os erros de login por uma grande margem - a tabela acima se aplica a ambos, mas a criação é onde reside a maior parte do volume.

A seguir, nos aprofundaremos em `NotAllowedError` porque é o que você verá com mais frequência e o que as equipes interpretam mal com mais frequência.

## 3. NotAllowedError: A operação expirou ou não foi permitida

O `NotAllowedError` muitas vezes parece "chaves de acesso falharam", mas geralmente é a plataforma informando que o usuário não concluiu a interface do SO. O segredo é dividi-lo em categorias nas quais você possa agir.

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| 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 esses aparecem como `error.name === "NotAllowedError"`. O `error.message` difere de acordo com o mecanismo do navegador e a causa subjacente, mas o resultado é o mesmo: a cerimônia não foi concluída.

Isso se aplica tanto ao **login quanto à criação de chaves de acesso**. Durante o login (Conditional UI, modal com ou sem lista de permissões), `NotAllowedError` normalmente significa que o usuário não concluiu a cerimônia. Durante a criação da chave de acesso, o mesmo erro surge por motivos diferentes: o usuário dispensou a caixa de diálogo de criação (a criação condicional não funcionou, ou a página perdeu o foco durante uma adição acionada automaticamente). O tipo de operação altera o que o erro significa e o que você deve fazer a respeito.

**O tempo de resposta é frequentemente um sinal subestimado.** Um erro com menos de um segundo após um clique geralmente é uma rejeição imediata (o ambiente não pode fazer isso, documento sem foco, recurso ausente). Um erro após alguns segundos é um cancelamento do usuário (ele viu a caixa de diálogo e decidiu não prosseguir). Um erro após 30+ segundos é um tempo limite. Em plataformas nativas, o tempo é especialmente importante: as viagens de ida e volta do autenticador, os prompts biométricos e as transferências do gerenciador de credenciais têm durações características que ajudam a separar "não funcionou" de "o usuário se afastou". Você ainda não pode distinguir facilmente se uma chave de acesso existia.

### 3.1 Desambiguar com contexto

Você não precisa de um sinal perfeito. Você precisa de contexto suficiente para evitar tratar todos os `NotAllowedError` da mesma forma. O iOS/Safari recebe atenção específica abaixo porque possui restrições exclusivas (requisitos de ativação do usuário em versões anteriores), mas em volume de erro bruto, o Windows e os navegadores Chromium geralmente geram mais `NotAllowedError` do que qualquer outra plataforma. Esses sinais geralmente o levam a 80% do caminho:

| **Sinal** | **Significado provável** | **O que fazer a seguir** |
| --- | --- | --- |
| Falha imediata (`<1s`) | Rejeição do ambiente: sem capacidade, documento sem foco, superfície de criação condicional indisponível | Verificar detecção de recursos; garantir que o documento tenha foco; verificar se a operação é suportada nesta plataforma |
| Cancelamento rápido (1 a 3s) | Prompt surpresa / sem contexto | Alterar o tempo do prompt; adicionar período de espera (cooldown) após o cancelamento |
| Cancelamento do usuário (3 a 15s) | O usuário viu a caixa de diálogo e optou por não prosseguir | UX esperada; restaurar a interface + mostrar alternativa |
| Tempo limite (30s+) | A cerimônia atingiu o tempo limite sem ação do usuário | Classificar como "não concluído"; considerar se o prompt foi notado |
| UI QR/híbrida aparece antes da falha | Nenhuma credencial local disponível neste dispositivo. Nota: detectar confiavelmente as decisões do código QR antes que elas aconteçam requer uma camada de [inteligência de chaves de acesso](https://docs.corbado.com/corbado-connect/features/passkey-intelligence) que saiba se uma credencial utilizável existe no dispositivo atual. | Restringir as ofertas de chaves de acesso; tornar "Usar telefone" explícito; reduzir códigos QR surpresa |
| Concentrado no iOS/Safari e acionado sem um clique/toque | Ativação do usuário ausente | Iniciar a cerimônia a partir de um gesto real do usuário |
| Durante a criação condicional ou adição automática | Preenchimento automático não disponível, a credencial já existe, ou a página perdeu o foco. Os erros de criação condicional podem aparecer repentinamente e em alto volume quando o recurso é lançado, tornando esta uma das maiores fontes de erro da noite para o dia. | Ver criação condicional; verificar o estado de visibilidade do documento; usar `getClientCapabilities()` para verificar o suporte a `conditionalCreate` antes de tentar a chamada |

É também por isso que `NotAllowedError` raramente deve ser visível para o usuário. Não é uma mensagem sobre a qual o usuário possa agir.

A classificação de contexto também é onde as taxas de sucesso se dividem mais acentuadamente. A [análise da taxa de sucesso de autenticação por chaves de acesso do Corbado Passkey Benchmark 2026](https://www.corbado.com/passkey-benchmark-2026/passkey-authentication-success-rate) mede a conclusão do primeiro trimestre de 2026 em 55-95% para fluxos com identificador primeiro em dispositivos desconhecidos versus 95-99% para retornos de dispositivos conhecidos em implantações B2C de grande escala. O identificador primeiro na web do iOS atinge a conclusão de 85-95% (% CDA 0-5%), na web do Android em 70-85% (% CDA 5-10%) e na web do macOS em 70-85% (% CDA 10-15%), enquanto a web do Windows fica em 45-60% de conclusão de identificador primeiro com % CDA em 55-65% no Windows 11 e 40-55% no Windows 10. Ler o volume de `NotAllowedError` sem separar contextos de dispositivos conhecidos versus desconhecidos confunde dois regimes de sucesso fundamentalmente diferentes.

Uma nuance que importa em produção: alguns agentes de usuário podem expor tempos limites como `TimeoutError`, mas muitas equipes ainda veem os tempos limites colapsarem em `NotAllowedError` nos painéis. De qualquer forma, trate os tempos limites como "cerimônia não concluída" e classifique usando o tempo mais o contexto.

### 3.2 Tratamento de UX: torne o cancelamento uma saída normal

Quando a tela do SO for fechada ou o tempo expirar, sua UI deve se recuperar imediatamente e reagir de forma suave. Um conjunto prático de regras:

- restaurar a interface de login (sem spinners rodando)
- manter o estado do identificador (não forçar nova entrada)
- mostrar uma alternativa visível na mesma tela
- evitar banners assustadores para resultados esperados

Além do básico:

- Trate o primeiro aborto como normal e ofereça uma nova tentativa com uma explicação calma. Só depois de um segundo aborto você deve sugerir métodos alternativos.
- Permita até três prompts de criação antes de um tempo de espera (cooldown) para que os usuários surpresos tenham uma segunda chance.
- Divida a contagem de erros entre criação e logins para que você compare coisas semelhantes.
- Segmente as taxas de erro por SO, navegador e dispositivo para que você possa identificar onde o atrito realmente reside.

Se os seus "cancelamentos" são genuinamente altos, o próximo passo é corrigir as causas raiz por trás deles: tempo do prompt, surpresas de QR e baixa disponibilidade.

### 3.3 Correções de engenharia que reduzem o NotAllowedError

Comece com as mudanças que movem as métricas rapidamente:

- Corrigir o momento do prompt e a ativação do usuário (especialmente no iOS/Safari).
- Reduzir surpresas QR/híbridas.
- Restringir ofertas para que as chaves de acesso sejam exibidas quando a probabilidade de sucesso for alta.
- Usar padrões que evitam avisos quando nenhuma credencial local existe.
- **Lidar com a instabilidade da rede:** Erros de rede durante a verificação costumam se manifestar como falhas genéricas no lado do cliente. Implemente uma fila offline para os registros de telemetria de modo que você não perca os dados de erro quando a conexão do usuário cair durante a cerimônia.
- **Restringir cerimônias com APIs de detecção** para que falhas de ambiente não inflem o número do seu `NotAllowedError`. Comece com `isUVPAA()` como o portão mais básico e use `getClientCapabilities()` para verificações mais detalhadas (criação condicional, obtenção condicional, transporte híbrido, autenticador de plataforma). Esteja ciente de que as APIs de detecção podem quebrar com atualizações do SO: o iOS 26.2 lançou um bug no WebKit em que `isUVPAA()` retorna `false` em todos os navegadores baseados em WKWebView, embora as chaves de acesso funcionem bem, causando picos repentinos de `NotAllowedError` para 10 a 25% dos usuários do iOS.

### 3.4 Nota sobre nomes de erro em evolução

Nomes de erros são um alvo móvel. Há propostas em andamento para adicionar erros de WebAuthn mais granulares (por exemplo, para separar "nenhuma credencial disponível" de "usuário cancelado"). Em fevereiro de 2026, isso não estava implementado em nenhum navegador, portanto, ainda vale a pena criar suas próprias categorias de motivo com base no contexto e no tempo. Se você quiser acompanhar esse trabalho, consulte a [questão #2062 do WebAuthn](https://github.com/w3c/webauthn/issues/2062) e a [explicação "New Error Codes"](https://github.com/w3c/webauthn/wiki/Explainer%3A-New-Error-Codes-%282024-Edition%29).

Os nomes de erro restantes são menos frequentes, mas ainda vale a pena entendê-los quando aparecem.

## 4. AbortError: A operação foi abortada

`AbortError` é incomum em volume em comparação com `NotAllowedError`, mas quando aparece é altamente diagnóstico: geralmente significa que a cerimônia não terminou porque seu aplicativo invalidou a solicitação - ocorreu navegação, o estado mudou ou uma segunda solicitação foi iniciada.

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| 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.` |

Causas de produção comuns incluem:

- chamadas simultâneas ao WebAuthn (dois prompts competindo)
- mudança de rota/re-renderização durante uma cerimônia em andamento
- chamada a `AbortController.abort()` durante repetições ou limpeza de estado

Para corrigir isso, concentre-se em tornar a cerimônia uma "seção crítica":

- permita apenas uma solicitação em andamento por vez
- bloqueie a navegação durante a cerimônia (ou cancele de forma limpa e restaure a interface)
- trate o aborto como um fluxo de controle normal: mostre um botão de repetição e um método alternativo

Se você observar o `AbortError` concentrado em superfícies embutidas ou aplicativos de vários domínios, o próximo balde a verificar será o `SecurityError`.

## 5. SecurityError: WebAuthn não é suportado em sites com erros de certificado TLS

`SecurityError` é o navegador dizendo a você: "este contexto não tem permissão para fazer o que você pediu". Na prática, quase sempre é uma configuração, não um comportamento do usuário. Em implantações de produção maduras, o `SecurityError` é raro porque esses problemas geralmente são detectados durante os testes de integração. Se aparecer em produção, geralmente significa que um novo domínio, contexto de incorporação ou destino de implantação foi adicionado sem a configuração correta do WebAuthn.

Causas comuns incluem:

- incompatibilidade de ID de RP / origem (configurações de vários domínios)
- restrições de incorporação de origem cruzada (iframes)
- contexto inseguro (não HTTPS) ou permissões/políticas bloqueadas
- `.well-known/webauthn` ou `.well-known/assetlinks.json` mal configurado, ausente ou temporariamente indisponível. Problemas de rede durante a janela crítica em que o navegador busca esses arquivos causarão falhas. Um ponto cego comum: se sua página inicial estiver fora do ar para manutenção, os arquivos well-known também estarão offline, interrompendo as cerimônias de chaves de acesso em todas as partes confiáveis que dependem deles.

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| Chrome, Edge | `SecurityError: WebAuthn is not supported on sites with TLS certificate errors.` |
| Qualquer 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.` |

Em produção, `SecurityError` é raro - quase sempre são detectados durante os testes de integração. Quando aparecem, o erro de certificado TLS é o mais comum.

O ciclo de depuração mais rápido é:

- registre a origem e as entradas de ID de RP que você usou
- reproduza no mesmo contexto (nível superior vs iframe, domínio de produção vs homologação)
- se você incorporar login, confirme se a política de permissões está configurada (por exemplo, `publickey-credentials-create` / `publickey-credentials-get`): [MDN Permissions-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Permissions-Policy/publickey-credentials-create)
- verifique a sua estratégia de domínio
- se você usar iframes, valide as políticas de recursos

Uma vez tratado o `SecurityError`, o próximo grupo a ser levado a sério é o conjunto de erros que muitas vezes indicam bugs de implementação: `InvalidStateError`, `ConstraintError` e `DataError`.

## 6. InvalidStateError, ConstraintError, DataError: tratar como bugs de implementação

Esses erros devem ser raros em uma implementação de chaves de acesso madura. Quando aparecem, geralmente indicam que a geração da opção está errada para um segmento ou que o fluxo está no estado errado.

### 6.1 InvalidStateError: "credenciais já registradas na parte confiável"

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| 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:

- registro: você tentou criar uma credencial que já existe (duplicada)
- login: menos comum; muitas vezes significa que o fluxo/estado é inconsistente para a plataforma

Tratamento prático:

- se acontecer em registro manual, trate como "já inscrito" e direcione de acordo
- garanta que `excludeCredentials` liste todos os IDs de credenciais existentes para o usuário, de modo que o autenticador possa detectar duplicatas
- durante a criação condicional, `InvalidStateError` é esperado e deve ser ignorado silenciosamente: significa que já existe uma chave de acesso no provedor. O mesmo se aplica a `NotAllowedError` e `AbortError` durante a criação condicional (consulte [criação condicional no Chrome](https://developer.chrome.com/docs/identity/webauthn-conditional-create)).

### 6.2 ConstraintError

Significado típico: o autenticador não pode satisfazer as restrições solicitadas.

Gatilhos comuns:

- falta de bloqueio de tela do dispositivo (especialmente Android): a plataforma exige verificação biométrica ou PIN, mas o dispositivo não tem tela de bloqueio configurada
- suposições muito rígidas sobre `authenticatorAttachment` ou chaves residentes
- requisitos de `userVerification` muito rígidos em segmentos onde não estão disponíveis

Correção: relaxe as restrições (onde aceitável) ou forneça um caminho alternativo. Em relação à falta de bloqueio de tela, considere detectar essa condição e orientar os usuários em vez de falhar silenciosamente (Android).

### 6.3 DataError

Significado típico: as entradas são malformadas ou inconsistentes.

Gatilhos comuns:

- erros de codificação (base64 vs base64url)
- IDs de credenciais inválidas / formatação de desafio

Correção: valide e normalize as entradas no limite onde você gera as opções de WebAuthn. Na prática, `DataError` é efetivamente ausente em sistemas de produção maduros - se a sua geração de opções for testada, você não verá isso nos painéis.

Se esses erros estiverem sob controle, a próxima pergunta é sobre a cobertura: os usuários estão falhando porque o ambiente não pode executar o WebAuthn da maneira que você espera?

## 7. NotSupportedError: O agente do usuário não suporta credenciais de chave pública

`NotSupportedError` é um sinal de cobertura, não de confiabilidade. Geralmente significa que um segmento não pode fazer o que você pediu (SO/navegador muito antigo, capacidade ausente, recurso não ativado).

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| 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` |

Os dois primeiros são `NotSupportedError` DOMExceptions genuínos. As entradas `TypeError` são tecnicamente um tipo de exceção diferente, mas representam a mesma classe de problema: o navegador ou ambiente não suporta o que você pediu. A família `TypeError` de serialização JSON é muito mais comum na prática do que a própria `NotSupportedError` DOMException (veja abaixo).

Causas comuns incluem:

- navegadores antigos/versões de sistema operacional que não suportam WebAuthn básico
- solicitar recursos do WebAuthn não disponíveis nessa plataforma
- tentativa de fluxos específicos da plataforma em dispositivos não suportados

**A família de serialização JSON é a maior fonte de falhas da classe `NotSupportedError` na produção.** Tecnicamente, estas aparecem como `TypeError` (método ausente), não como um `DOMException`, mas é onde você as encontrará. Duas causas básicas distintas:

1. **Navegador não suporta métodos de serialização JSON do WebAuthn.** O navegador tem `navigator.credentials`, mas não tem `PublicKeyCredential.parseCreationOptionsFromJSON` / `parseRequestOptionsFromJSON`. Isso representa cerca de 90% dessa família de erros, concentrando-se em versões mais antigas do Safari e do Chrome. Se a sua biblioteca cliente depende desses métodos sem uma alternativa, isso produzirá um volume significativo de erros.
2. **Extensões de gerenciadores de senhas quebram `.toJSON()`.** Extensões como Bitwarden, LastPass ou 1Password podem interceptar a cerimônia e retornar um objeto que parece uma credencial, mas não é uma instância real de `PublicKeyCredential`. Chamar `.toJSON()` nele lança uma exceção, retorna "undefined", ou o objeto é totalmente `null`. Isso é cerca de 10% da família, mas é especialmente confuso para depurar, pois as mensagens de erro diferem por navegador (Safari: "Can only call on instances of PublicKeyCredential"; Firefox: "does not implement interface PublicKeyCredential").

O tratamento deve ser direto e rápido:

- recorrer imediatamente a uma senha/OTP como alternativa
- registrar o segmento para que você possa quantificar as lacunas de cobertura
- evitar mostrar CTAs de chaves de acesso em segmentos que falharão de forma consistente

Se a cobertura parece adequada, mas as falhas ainda acontecem em segmentos específicos, você pode estar lidando com problemas da camada de plataforma exibidos como `UnknownError`.

## 8. UnknownError: Ocorreu um erro desconhecido ao falar com o gerenciador de credenciais

`UnknownError` é um genérico para falhas do autenticador/SO que não se mapeiam de maneira precisa para as outras categorias. Muitas vezes é transitório, mas também pode ter picos após atualizações do SO.

**O que você verá no console do navegador:**

| **Fonte** | **Mensagem de erro** |
| --- | --- |
| Chrome (Android) | `UnknownError: An unknown error occurred while talking to the credential manager.` |
| Qualquer navegador | `UnknownError: The operation failed for an unknown transient reason.` |
| Qualquer navegador | `UnknownError: Either the device has received unexpected request data, or the device has been reconfigured since the request was made.` |
| Qualquer 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` |

Tratamento prático:

- use uma UX amigável para novas tentativas (não "culpe o usuário")
- capture números do SO/build e o contexto do gerenciador/provedor de credenciais sempre que possível
- observe os picos específicos do segmento após as atualizações do SO

Uma fonte de nicho de erros que não se encaixa perfeitamente em nenhuma categoria de `DOMException`: **extensões de navegador de gerenciadores de senha** (como Bitwarden, LastPass, 1Password e outros) podem interceptar chamadas da API WebAuthn e retornar respostas não padronizadas. Embora pequenos em volume em comparação com cancelamentos do usuário, vale a pena acompanhá-los porque afetam segmentos de usuários específicos consistentemente e os sintomas são confusos: métodos ausentes no objeto de credencial retornado, tipos de erro inesperados ou respostas malformadas que não correspondem a nenhum erro WebAuthn documentado. Geralmente eles aparecem como `UnknownError` ou como exceções não classificadas. Se você vir picos de erro concentrados em navegadores específicos sem explicação no nível do SO, verifique se uma extensão do gerenciador de credenciais está envolvida.

Até agora cobrimos nomes de erro em navegadores da web. Mas se você também envia aplicativos nativos, o cenário de erros é diferente - e em alguns aspectos, significativamente melhor.

## 9. Uma palavra sobre aplicativos nativos (iOS e Android)

Tudo acima abrange os navegadores da web. Aplicativos nativos - iOS com o framework ASAuthorization, Android com o Credential Manager - compartilham as mesmas categorias fundamentais de erro, mas diferem de forma importante:

1. **"Nenhuma credencial" é um sinal distinto.** Na web, os navegadores combinam "nenhuma credencial disponível" e "usuário cancelou" no mesmo `NotAllowedError` por privacidade. Em nativo, usar `preferImmediatelyAvailableCredentials` no iOS (`ASAuthorizationController`) ou `setPreferImmediatelyAvailableCredentials(true)` no Android (`GetCredentialRequest`) diz ao SO para apenas apresentar as credenciais que já estão no dispositivo e falhar imediatamente se não houver nenhuma. Isso fornece um retorno limpo "nenhuma credencial" que a web não pode fornecer.

2. **O status do provedor de credenciais é visível.** Plataformas nativas em algumas condições podem informar quando nenhum provedor de credencial (Google Password Manager, iCloud Keychain, 1Password, etc.) está instalado, configurado, ou definido como padrão e reagir a isso. Na web, essas informações estão escondidas atrás de mensagens `NotAllowedError` opacas.

3. **As mensagens de erro são mais específicas.** Porque o usuário instalou o aplicativo - e assim estabeleceu uma relação de confiança com a parte confiável - o SO apresenta detalhes de diagnóstico maiores. As considerações de privacidade que forçam os navegadores da web a serem vagos não se aplicam da mesma forma quando o aplicativo já está no dispositivo. O iOS retorna mensagens localizadas no idioma do dispositivo do usuário. O Android retorna tipos de erro estruturados com cadeias de causas. Isso torna a depuração mais fácil, mas significa que seu tratamento de erros deve levar em consideração a localização e os formatos de erro específicos da plataforma.

### 9.1 iOS (Framework ASAuthorization)

O iOS apresenta os erros de chave de acesso através do framework ASAuthorization. Todos os erros chegam no retorno de chamada do delegado `authorizationController(controller:didCompleteWithError:)` como objetos `NSError`.

**Classifique por domínio + código, não pela string de mensagem.** O domínio de erro principal é `com.apple.AuthenticationServices.AuthorizationError` (`ASAuthorizationError.errorDomain`). Faça a conversão do erro com `let nsError = error as NSError` e combine em `.domain` e `.code`. Nunca compare com `.localizedDescription` em produção - as mensagens da Apple estão localizadas em 30+ idiomas e podem mudar de acordo com a versão do SO. As strings de mensagem listadas abaixo são úteis para reconhecer erros em logs, mas não são critérios de classificação.

**Códigos públicos do ASAuthorizationError:**

| **Código** | **Nome** | **Desde** | **O que significa** |
| --- | --- | --- | --- |
| 1000 | `Unknown` | iOS 13 | Não deve aparecer em produção. Captura geral. |
| 1001 | `Canceled` | iOS 13 | Usuário fechou a tela de chave de acesso. O erro mais comum em geral - o equivalente a `NotAllowedError`. Sinal limpo com `userInfo` vazio e sem erro subjacente. |
| 1002 | `InvalidResponse` | iOS 13 | Corrupção ao nível do framework. Raro na prática. |
| 1003 | `NotHandled` | iOS 13 | Nenhum provedor atendeu a solicitação. Verifique direitos e configurações do provedor de credenciais. |
| 1004 | `Failed` | iOS 13 | Falha genérica. O `localizedDescription` contém a verdadeira razão (ex. "Aplicativo com identificador X não está associado ao domínio Y"). O `userInfo` pode conter uma string `FailureReason`, mas `NSUnderlyingErrorKey` não está sempre preenchido - falhas de associação de domínio retornam nulo para o erro subjacente. |
| 1005 | `NotInteractive` | iOS 15 | Nenhuma credencial disponível ao usar `preferImmediatelyAvailableCredentials`. Este é o sinal claro de "não encontrado" - o equivalente do iOS a "nenhuma chave de acesso existe neste dispositivo". Nenhuma UI foi exibida. |
| 1006 | `MatchedExcludedCredential` | iOS 18 | Já existe uma chave de acesso para este RP neste dispositivo. Sinal claro para detecção de duplicidade - `userInfo` vazio, sem `NSUnderlyingErrorKey`. A classificação funciona sem correspondência de string. |
| 1007 | `CredentialImport` | iOS 18.2 | Importação de credencial falhou. |
| 1008 | `CredentialExport` | iOS 18.2 | Exportação de credencial falhou. |
| 1009 | `PreferSignInWithApple` | iOS 26 | Usuário prefere Iniciar Sessão com a Apple em vez de chave de acesso. Novo no iOS 26. |
| 1010 | `DeviceNotConfiguredForPasskeyCreation` | iOS 26 | Dispositivo sem senha ou configuração de iCloud Keychain. Bug conhecido no simulador do iOS 26: retorna 1010 mesmo quando a configuração está correta (não reproduzível em dispositivos físicos). |

A distinção mais importante para produção: **desde o iOS 18, credenciais duplicadas retornam seu próprio código de erro 1006 (`MatchedExcludedCredential`).** No iOS 17 e anteriores, as credenciais duplicadas ficavam ocultas dentro do código 1004 (`Failed`). No iOS 18+, a distinção é estrutural (código de erro diferente), não textual.

**Erros de tempo de execução comuns (referência de nível de log):**

Essas mensagens aparecem em `localizedDescription` ou em `userInfo` para cenários de falha específicos. Use-os para pesquisas de log e depuração, não para classificação programática.

| **Mensagem (localização em inglês)** | **Código subjacente** | **Notas** |
| --- | --- | --- |
| `Application with identifier <TeamID.BundleID> is not associated with domain X` | 1004 (`Failed`) | O entitlement Associated Domains do aplicativo não corresponde à parte confiável. Corrija o arquivo `apple-app-site-association` no seu servidor. |
| `Couldn't communicate with a helper application.` | 1004 (`Failed`) | A extensão do provedor de credenciais não respondeu. Transitório - repetir é apropriado. |
| `Request already in progress for specified application identifier.` | 1004 (`Failed`) | Uma solicitação ASAuthorization duplicada foi acionada enquanto uma estava pendente. Condição de corrida no aplicativo. |
| `Stolen Device Protection is enabled and biometry is required.` | 1004 (`Failed`) | Stolen Device Protection do iOS 17+ bloqueia auth biométrica em locais não familiares. Não acionável por desenvolvedores, mas vale a pena informar ao usuário. |
| `(AuthenticationServicesCore.ASCABLEClient.ClientError error 2.)` | Domínio separado | Falha no handshake Bluetooth para autenticação entre dispositivos (hybrid/CABLE). |
| `(AuthenticationServicesCore.ASCABLEClient.ClientError error 3.)` | Domínio separado | Falha de conexão Bluetooth para autenticação entre dispositivos. |

**Mensagens "nenhuma credencial" localizadas (código 1005):**

Quando `preferImmediatelyAvailableCredentials` está definido e não há chave de acesso, o iOS retorna o código 1005 (`NotInteractive`) com uma mensagem localizada no idioma do dispositivo do usuário. Isto é exclusivo dos aplicativos nativos - os navegadores da web nunca expõem esse sinal. A mensagem sempre começa com `A operação não pôde ser concluída.` seguida do texto localizado:

| **Idioma** | **Mensagem** |
| --- | --- |
| Chinês (Simplificado) | `没有可用于登录的凭证。` |
| Vietnamita | `Không có sẵn thông tin để đăng nhập.` |
| Árabe | `لا تتوفر بيانات اعتماد لتسجيل الدخول.` |
| Espanhol | `No hay ninguna credencial disponible para iniciar sesión.` |
| Chinês (Tradicional) | `沒有可用於登入的憑證。` |
| Coreano | `로그인을 위한 자격 증명이 없습니다.` |
| Francês (Canadá) | `Aucun identifiant disponible pour la connexion.` |
| Português (Brasil) | `Nenhuma credencial disponível para login.` |
| Francês (França) | `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.` |

Os dispositivos de localização em inglês normalmente resolvem "nenhuma credencial" no nível da API antes que o framework ASAuthorization retorne um erro localizado, e é por isso que nenhuma variante em inglês aparece acima. Programaticamente, compare sempre o código 1005 em vez de analisar essas strings.

### 9.2 Android (API Credential Manager)

O Android apresenta os erros das chaves de acesso pela API Credential Manager (`androidx.credentials`). As mensagens de erro incluem uma mensagem principal e frequentemente uma `cause` (causa) com detalhes adicionais. Em comparação com o iOS, o Android fornece tipos de erro mais estruturados e causas mais explícitas para problemas de configuração.

**Cancelamento pelo usuário e detecção de credenciais:**

| **Erro** | **Notas** |
| --- | --- |
| `User cancelled the operation` | O usuário fechou o prompt de chave de acesso. Equivalente ao `NotAllowedError`. Nota: O Credential Manager também retorna `User canceled the request` de um caminho de código diferente - ambos são idênticos. |
| `Excluded credential matches existing credential` | Uma chave de acesso já existe para este ID de credencial. Equivalente a `InvalidStateError`. Diferente do iOS, a mensagem é distinta do cancelamento de usuário. |
| `No create options available.` | Nenhum provedor de credenciais qualificado pode tratar a solicitação de criação. Normalmente significa que o Google Play Services está desatualizado ou nenhum provedor suporta a criação de chave de acesso. |

**Erros de configuração e segurança:**

| **Erro** | **Notas** |
| --- | --- |
| `Passkeys not supported for this app` | Digital Asset Links (`assetlinks.json`) ausente ou não contém a impressão digital do certificado de assinatura do aplicativo. O equivalente a `SecurityError`. |
| `Https failed: respCode=301, url=https://<domain>/.well-known/assetlinks.json` | O arquivo `assetlinks.json` retorna um redirecionamento em vez de HTTP 200. O Android exige o arquivo na URL exata sem redirecionamentos. |
| `The incoming request cannot be validated` | O Credential Manager não pôde verificar a solicitação em relação ao Digital Asset Links. |
| `RP ID cannot be validated.` | A ID da parte confiável nas opções do WebAuthn não corresponde ao `assetlinks.json`. |
| `Screen lock is missing.` | Nenhum PIN, padrão, ou biométrica configurada no dispositivo. As chaves de acesso exigem a verificação do usuário. O equivalente a `ConstraintError`. |
| `Cannot find an eligible account.` | Nenhuma conta do Google no dispositivo é qualificada para a criação da chave de acesso (raro, normalmente para configurações corporativas personalizadas). |

**Erros de plataforma e autenticador:**

| **Erro** | **Notas** |
| --- | --- |
| `Unsuccessful result from folsom activity.` | Falha interna do Google Play Services. "Folsom" é um componente GMS para operações de chaves de acesso. Transitório - repetir é apropriado. |
| `Can't find the proper key to decrypt the private key from WebauthnCredentialSpecifics.` | Uma chave de acesso sincronizada existe, mas o dispositivo não pode descriptografar sua chave privada. O estado de sincronização do Google Password Manager é inconsistente - a credencial foi sincronizada a partir de outro dispositivo, mas a chave de descriptografia não está disponível. Não acionável por desenvolvedores. |
| `Operation was interrupted` (cause: `The UI was interrupted - please try again.`) | A interface do Credential Manager foi interrompida por outra atividade (chamada recebida, rotação da tela, aplicativo em segundo plano). O equivalente ao `AbortError`. |
| `Unknown credential error` | Erro genérico quando nenhum tipo de erro específico se aplica. Normalmente transitório. |
| `timeout` (cause: `Canceled`) | A operação do Credential Manager expirou antes que o usuário concluísse a verificação biométrica. |

## 10. Juntando tudo: a taxonomia de erros

O diagrama a seguir mostra como todas as camadas discutidas acima - Infraestrutura, Ambiente, Tipo de operação, Classificação e Detecção - se conectam de ponta a ponta. É o modelo mental que você deve ter em mente ao projetar seu rastreamento de erros.

```mermaid
flowchart TD
    %% Global Styles
    classDef expected fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef unexpected fill:#ffebee,stroke:#c62828,stroke-width:2px;
    classDef network fill:#fff3e0,stroke:#ef6c00,stroke-dasharray: 5 5;
    classDef env fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px;
    classDef action fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;

    %% --- LEFT SIDE: NETWORK & SERVER ---
    subgraph Infrastructure ["Infraestrutura (Servidor/Rede)"]
        direction TB
        ServerErr["Erro no Lado do Servidor<br/>500 / Erro Lógico"]:::network
        NetErr["Erro de Rede<br/>Tempo Limite / 400 Solicitação Incorreta"]:::network

        ServerErr & NetErr -->|Manifesta-se como| ClientManifest["Erro Genérico no Lado do Cliente"]
    end

    %% --- CENTER: THE ENVIRONMENT STACK (From Sketch) ---
    subgraph Environment ["O Ambiente (Lado do Cliente)"]
        direction TB

        %% Layer 1: Platform Type
        subgraph Type ["Camada 1: Plataforma"]
            Web["Web / Navegador"]
            Native["Nativo / App"]
        end

        %% Layer 2: OS Context
        subgraph OS_Layer ["Camada 2: SO e Versão"]
            OS_Web["SO: Windows, macOS, Linux"]
            OS_Nat["SO: iOS, Android"]
            OS_Ver["Versão do SO / Configurações<br/>(Bloqueio de Tela, Biometria)"]

            Web --> OS_Web
            Native --> OS_Nat
            OS_Web & OS_Nat --> OS_Ver
        end

        %% Layer 3: Client Software
        subgraph Client_Layer ["Camada 3: Software Cliente"]
            Browser["Navegador: Chrome, Safari, Edge<br/>+ Versão"]
            App["App Nativo / WebView<br/>+ Versão do App"]

            OS_Ver --> Browser
            OS_Ver --> App
        end

        %% Layer 4: WebAuthn Operation
        subgraph Op_Layer ["Camada 4: Operação WebAuthn"]
            OpType{"Tipo de Operação"}

            Login["Login<br/>(navigator.credentials.get)"]
            Reg["Registro<br/>(navigator.credentials.create)"]

            Browser & App --> OpType
            OpType --> Login
            OpType --> Reg
        end

        %% Layer 5: Sub-types & Complexity
        subgraph Modality ["Camada 5: Modalidade e Complexidade"]
            Sub_CUI["CUI / Conditional UI"]
            Sub_Auto["Operação Automática"]
            Sub_CDA["CDA / Autenticação Entre Dispositivos"]

            Login & Reg --> Sub_CUI
            Login & Reg --> Sub_Auto
            Login & Reg --> Sub_CDA
        end
    end

    %% --- BOTTOM: CLASSIFICATION & ACTION (The "What here?" section) ---
    subgraph Analysis ["Análise de Erros e Execução"]
        direction TB

        %% Classification
        Classification{"Classificação"}

        Exp["Erro Esperado<br/>(Usuário Abortou a Cerimônia)"]:::expected
        Unexp["Erro Inesperado<br/>(Falha no Sistema/Desconhecido)"]:::unexpected

        ClientManifest --> Classification
        Sub_CUI & Sub_Auto & Sub_CDA --> Classification

        Classification --> Exp
        Classification --> Unexp

        %% Detection Logic
        subgraph Detection ["Objetivos da Detecção"]
            P1["P1: Problemas no Login"]
            P2["P2: Problemas na Criação"]
            Baseline["Detectar Desvio Base<br/>(Aumento de Esperados)"]
            NewErr["Detectar Novas Anomalias<br/>(Aumento de Inesperados)"]
        end

        Exp --> Baseline
        Unexp --> NewErr
        Exp & Unexp --> P1 & P2

        %% Actionable Outcomes
        subgraph Action ["Ações de Mitigação"]
            Fix["Implantar Correção Rápida / Nova Versão"]:::action
            Fallback["Ativar Recurso Automático<br/>(Desativar Chave de Acesso)"]:::action
        end

        P1 & P2 & NewErr --> Fix
        P1 & P2 & NewErr --> Fallback
    end

    %% Connectors
    Infrastructure -.-> Environment
```

A descoberta principal: um `error.name` bruto só faz sentido quando você sabe qual camada do Ambiente o produziu, qual Operação estava em execução e se o erro era Esperado ou Inesperado. As seções a seguir cobrem o que registrar e como agir.

## 11. O que registrar para que os erros se tornem depuráveis

A maior parte da classificação de erros neste artigo pode ser feita usando apenas sinais do lado do cliente. Um SDK de observabilidade focado no frontend captura contexto suficiente para classificar a grande maioria dos erros do WebAuthn. É também assim que o SDK de observabilidade do Corbado é arquitetado: a camada do cliente trata da atribuição do erro, do tempo de resposta, do contexto da operação e da detecção da plataforma. O registro no servidor adiciona uma segunda camada para falhas que apenas o back-end pode ver.

O requisito principal: cada tentativa deve ser conectável de ponta a ponta. Um ID de correlação compartilhado (por exemplo, `auth_flow_id`) conecta o contexto do lado do cliente ao resultado da verificação do servidor.

### 11.1 Sinais no lado do cliente (Frontend SDK)

| **Sinal** | **Por que importa** |
| --- | --- |
| `error.name` + categoria de motivo normalizada | Erro bruto do navegador + sua classificação |
| Tipo de operação | Conditional UI, login modal, criação manual, criação condicional, adição automática. **CDA (Autenticação Entre Dispositivos)** é uma parte complexa própria. |
| Contexto do Ambiente Completo | SO + Versão, Navegador + Versão, **Marca/Modelo de Hardware**, **Configurações do Autenticador** (ex., GPM habilitado?) |
| Contexto do Autenticador / gerenciador de credenciais | Extensão e problemas do provedor |
| Tempo até o erro a partir do início da operação | Rejeição imediata (`<1s`) vs cancelamento pelo usuário (1 a 15s) vs tempo limite (30s+) |
| Rede / Status da Conexão | Erros de rede muitas vezes se manifestam como erros de cliente. Rastrear se o usuário estava offline e **enfileirar registros** para enviar quando a conectividade for restaurada. |
| Se a UI QR/híbrida apareceu | Falha local vs entre dispositivos |
| ID de correlação (`auth_flow_id`) | Vincular com os registros do servidor |

### 11.2 Sinais no lado do servidor (Verificação de Backend)

As falhas de verificação do servidor ocorrem depois que o navegador retorna uma credencial e um desafio assinado. Esses devem ser erros estruturados com códigos explícitos, e não misturados na mesma categoria dos nomes de `DOMException` do lado do cliente. Veja: implementação do servidor WebAuthn.

| **Sinal** | **Por que importa** |
| --- | --- |
| Incompatibilidade de desafio / desafio expirado | Problemas de tempo de sessão ou repetição |
| Incompatibilidade de Origem / ID de RP | Bugs de configuração de vários domínios |
| Assinatura inválida / credencial não encontrada | Credencial excluída ou corrompida. Caso comum: login com Conditional UI usando uma chave de acesso que o usuário já apagou no servidor. Use a API Signal para manter as listas de credenciais de cliente e servidor sincronizadas. |
| Incompatibilidade do identificador de usuário (user handle) | Problemas de mapeamento de contas |
| ID de correlação (`auth_flow_id`) | Vincular com o contexto do lado do cliente |

Se você quer um modelo de funil completo (desistências por etapa e conversão entre as etapas), veja: telemetria de chaves de acesso para entender as desistências.

[Watch on YouTube](https://www.youtube.com/watch?v=wnrXJzvBjsU)

Com esses dados em vigor, a conclusão torna-se simples: a maioria dos "erros" torna-se correções de interface do usuário, correções de cobertura ou correções de configuração. Mas construir e manter esta classificação você mesmo é um trabalho contínuo significativo.

## 12. Além dos nomes de erro: como o Corbado transforma erros brutos em sinais acionáveis

A lista de verificação de log acima captura sinais brutos. Na produção em escala, o `error.name` isolado não é suficiente. Construir esta classificação por conta própria é um trabalho contínuo significativo: as mensagens de erro mudam a cada lançamento de navegador e SO, os provedores de gerenciamento de senhas enviam atualizações que alteram o comportamento da cerimônia e novas assinaturas de erro aparecem a cada lançamento de recurso.

### 12.1 Por que o `error.name` isolado não é suficiente

O mesmo `NotAllowedError` pode significar seis coisas diferentes, dependendo de três dimensões que os navegadores não separam para você:

| **Dimensão** | **O que os navegadores fornecem** | **O que você realmente precisa** | **Exemplo** |
| --- | --- | --- | --- |
| **Contexto da operação** | `NotAllowedError` | Foi um Conditional UI, login modal, criação manual, criação condicional, ou adição automática? | O Android retorna o mesmo "erro desconhecido" para um descarte de login (esperado) e uma falha de criação (inesperada) |
| **Tempo** | Sem dados de duração | Rejeição imediata (`<1s`) vs cancelamento pelo usuário (1 a 15s) vs tempo limite (30s+) | 200ms = rejeição do ambiente; 5s = usuário viu a caixa de diálogo e cancelou; 35s = tempo limite |
| **Plataforma + autenticador** | `error.name` genérico | SO, navegador, versão, gerenciador de credenciais para cada erro | "usuário fechou o diálogo" no Chrome e "preenchimento automático não disponível" no Safari aparecem como `NotAllowedError` |

### 12.2 O que o SDK de observabilidade do Corbado captura

Este é o problema que o [SDK de observabilidade do Corbado](https://www.corbado.com/pricing) foi projetado para resolver. É uma integração frontend leve que se sobrepõe à sua implementação de chaves de acesso existente, funciona com qualquer servidor WebAuthn e qualquer IDP, e classifica automaticamente cada erro WebAuthn em todas as três dimensões:

| **Capacidade** | **O que ele faz** |
| --- | --- |
| **Atribuição de erro** | Captura SO, versão do SO, navegador, versão do navegador e autenticador a cada tentativa de cerimônia |
| **Modo de operação** | Conecta cada erro à operação específica (Conditional UI, login modal, criação manual, criação condicional, adição automática) para que o mesmo `NotAllowedError` se resolva em diferentes causas raiz |
| **Tempo desde o início** | Registra a duração desde o início da cerimônia para distinguir rejeições imediatas, cancelamentos de usuários e limites de tempo sem precisar adivinhar |
| **Classificação inteligente de erros** | Corresponde ao contexto completo do erro (não apenas o nome), normalizando nos vários **Ambientes** (SO, Hardware, Configurações). Prioriza grupos de erros distintos como **CDA** vs. Local, e distingue erros **Esperados (Aborto pelo Usuário)** de **Inesperados (Falha do Sistema)**. |
| **Fragmentação de gerenciador de senhas** | Detecta quando extensões de gerenciadores de credenciais (Bitwarden, 1Password, LastPass) interceptam as cerimônias e retornam respostas não padronizadas, separando as falhas causadas pelas extensões das falhas da plataforma |

Esta é a camada **Observe**: visibilidade do que está acontecendo, sem precisar mudar sua implementação.

### 12.3 Duas formas de depurar: Top-Down e Bottom-Up

A interface de gestão do Corbado suporta dois caminhos de investigação:

**De cima para baixo (do painel à causa raiz):**

1. **Monitore para dois tipos distintos de anomalias:**
    - **Aumento de Erros Esperados (Desvio da Linha de Base):** Um ambiente específico (ex. iOS 18.2 no iPhone 15) sofreu um aumento gradual nos "cancelamentos de usuários"? Isso geralmente indica atritos de interface do usuário introduzidos por uma atualização do SO.
    - **Aumento de Erros Inesperados (Picos):** Um erro completamente novo ou um aumento repentino nas falhas. Isso geralmente indica uma mudança drástica (uma atualização de pilha no IDP) ou uma regressão em uma nova versão de navegador.
2. **Priorizar pelo impacto:**
    - **P1: Problemas de Login.** Se as taxas de sucesso no login caírem, alerte imediatamente.
    - **P2: Problemas de Criação.** Monitore as tendências, mas evite acordar os engenheiros por causa de picos de "cancelamento do usuário" em fluxos de criação.
3. **Aprofundamento no Ambiente:** Use as dimensões granulares (Hardware, Configurações de Auth) para isolar se o problema é global ou se é específico para "dispositivos Samsung com Android 14".
4. **Mitigação:** Se um pico crítico for detectado, tenha um **Kill Switch** pronto. Desative as chaves de acesso para esse ambiente específico de forma manual ou automática e utilize OTPs/Senhas como reserva para manter as taxas de login altas enquanto você investiga.

**De baixo para cima (de padrões de erro a impactos):**

1. Comece pela tela de classificação de erro. Revise os padrões de erros classificados e os seus respectivos volumes.
2. Refine os mapeamentos de erro à medida que novos padrões surgem (ex. uma versão nova de navegador gerando uma mensagem de erro diferente).
3. Os erros são interligados às alterações nos KPIs e apresentados como anotações nos painéis, logo, um pico num padrão de erro em particular é automaticamente conectado à métrica que ele afetou.

Ambos os caminhos convergem: o de cima para baixo indica que algo está errado e o de baixo para cima diz por que. O [Assistente de Análise com IA](https://www.corbado.com/ai-analytics-assistant) conecta ambos ao permitir que você faça perguntas utilizando linguagem natural acerca dos dados de erros e métricas de adoção.

As equipes que desejam agir sobre estes sinais podem avançar para a funcionalidade **Adopt**, a qual incorpora [inteligência de chaves de acesso](https://docs.corbado.com/corbado-connect/features/passkey-intelligence) para proteger cerimônias automaticamente, otimizar prompts de inscrição e consertar os estados corrompidos das chaves de acesso. Para ambientes regulamentados ou implementações em larga escala, a funcionalidade **Enterprise** traz alojamento para inquilino único, integração SIEM e configuração compatível com a PSD2.

## 13. Conclusão

Os nomes de erro do WebAuthn não são um veredito. Eles são pistas - e só se tornam acionáveis quando você os conecta ao tipo de operação, ao tempo e ao contexto da plataforma.

- **O que os nomes de erro de WebAuthn mais comuns significam na produção?** A maior parte é mapeada a um pequeno número de camadas: o controle de fluxo pelo usuário (`NotAllowedError`), ciclo de vida ou concorrência da aplicação (`AbortError`), contexto/configuração de segurança (`SecurityError`) ou falhas em estados e opções (`InvalidStateError`, `ConstraintError`, `DataError`). A grande maioria do volume provém de `NotAllowedError`, sendo a maior parte disso um comportamento previsível (como o usuário que dispensa o prompt).
- **Como desambiguar o `NotAllowedError`?** Recorra ao tempo de resposta (rejeição imediata vs cancelamento pelo utilizador vs expiração de tempo limite), uma indicação da interface QR/híbrida (incompatibilidade de disponibilidade), o contexto em que a ativação acontece pelo utilizador (especialmente em iOS/Safari) bem como o tipo da operação (se é login com Conditional UI vs login em ecrã modal vs criação de chaves de acesso vs criação condicional). Evite tratar a totalidade de `NotAllowedError` enquanto uma mesma modalidade de falha.
- **Por que o tipo de operação importa?** O mesmo `error.name` num login com Conditional UI é um sinal inteiramente diferente daquilo que reflete durante a criação condicional ou aquando a criação explícita da chave de acesso (no momento em que o usuário recusa as caixas de diálogo). O registro minucioso da modalidade de operação atrelado ao erro será aquilo que possibilita a transmutação do `NotAllowedError` vago numa rubrica executável.
- **Que contexto mínimo faz com que os erros sejam analisáveis?** Reúna e capture `error.name`, a natureza da operação executada, o momento exato em que a falha desponta, o tipo de trajetória a percorrer e a forma da interface QR/híbrida. Guarde ainda OS/navegador/equipamento (com as versões envolvidas), um identificador que agrupe essas propriedades (`auth_flow_id`) e recusas provenientes da verificação servidor tratadas num padrão rigoroso sob a forma de códigos formais.

A título de duas advertências principais aplicáveis em toda linha de erros: não demonstre falhas exatas e textuais dos navegadores em causa aos utilizadores finais, ao longo do tempo procure fornecer um escape compreensível — mantenha isoladas tentativas realizadas pontualmente nos terminais sem que elas interfiram em conexões originadas por via QR ou mesmo na ponte entre dispositivos — e tudo isso, devido às discrepâncias notórias nos causadores dessas irregularidades. Escalando esses processos, sustentar a devida classificação de falhas navegando através de browsers distintos, variados graus nas ramificações dos Sistemas e provedores de chaves é um esforço exaustivo. Contemple, desse modo, a opção de utilizar um kit de SDK especializado com a capacidade de manter esse conjunto já construído.

## Perguntas Frequentes

### Como saber a diferença entre um usuário cancelando um prompt de chave de acesso e o dispositivo não tendo uma chave de acesso?

Na web, os navegadores combinam os dois casos em um `NotAllowedError` por razões de privacidade, portanto não será possível estabelecer distinção com base no evento isolado. Tire proveito da duração atestando que sob o prazo limite de apenas 1 segundo trata-se de um conflito ambiental inerente ao terminal e limitações de disponibilidade. Na faixa de tempo limite contígua a um valor de até 15 segundos o veredito sugere a intenção visual por meio dos usuários frente aos parâmetros oferecidos no prompt. Em aplicações de cariz nativo iOS ou Android, utilizar `preferImmediatelyAvailableCredentials` antes da sua invocação lhe fornece acesso direto ao sinalizador puro traduzível por "sem credenciais disponíveis" (no iOS, código exato 1005; já no Android, equivalente no pedido de `GetCredentialRequest`) antes da projeção visual dos botões expostos.

### Por que minha taxa de erro do WebAuthn é tão alta, mesmo que as chaves de acesso pareçam estar funcionando para a maioria dos usuários?

Em ambientes implementados de grande magnitude focados em chaves de acesso devidamente ajustadas, ultrapassando um valor em torno de 95% do panorama assinalado por WebAuthn representam rejeições naturais inerentes ao desinteresse circunstancial vindo da parte do consumidor, deixando as questões internas por si intactas. Registrar picos sob valores unificados do `error.name` misturando na amostra as abstenções sem categorizar em falhas genuínas inflaciona métricas que na realidade se escondem na categoria em constante sobressalto `NotAllowedError`. Fracione todos esses cômputos num âmbito analítico através dos propósitos acoplados em subescalas e categorize a rejeição manual sem englobar sob constrangimentos de erro inesperado tipo `SecurityError`, `ConstraintError` e os que afetam preenchimento dos dados com relevo ao `DataError`.

### O que significa o código ASAuthorizationError 1005 no iOS e como devo usá-lo?

O erro equivalente ao número iOS 1005 (`NotInteractive`) pressupõe que as ferramentas atreladas às credenciais passkey não correspondiam ao catálogo inerente ao aparelho perante o disparo imediato invocado com `preferImmediatelyAvailableCredentials` mediante diretriz explícita impulsionada no `ASAuthorizationController`, ocorrendo o ocultamento perante a exposição na interface visual ao utilizador. A vertente denota em si um indicativo autêntico do modelo ausente não verificável nos navegadores web graças aos fatores e garantias em volta da privacidade. Mantenha as abordagens categóricas sob esse enquadramento de números descartando correlações linguísticas baseadas no conteúdo estendido da rubrica descrita sob a chancela `localizedDescription`, de resto, lembre-se do fato das locuções fornecidas aos usuários provindas da base de dados baseada em Apple encontrarem-se espalhadas no mínimo em mais de trinta vertentes localizadas, e com variações imprevistas consoante as novas construções dos sistemas operacionais adjacentes.

### Como devo lidar com NotAllowedError durante um fluxo de criação condicional ou adição de chaves de acesso acionada automaticamente?

No contexto dos mecanismos na modalidade de registro sob escrutínios condicionais, o reflexo devolvido no cômputo englobando o `NotAllowedError`, `AbortError` interligado ao `InvalidStateError` abrange vertentes com comportamentos regulares. Abstraia a existência em pormenor, abstendo de ressalvas as discrepâncias sem apresentar de forma alarmante num balão explícito focado a expor o evento ao utilizador sob a chancela dos equívocos de natureza errónea. É previsível em cenários abrangendo `NotAllowedError` quando as caixas em branco reservadas a facilitar no ato e o preenchimento não estejam abertas nem encontrem margem funcional visando atuar num plano focado ou subjacente na vista corrente; adicionalmente com relevo no cenário coberto com o aspeto do registo `InvalidStateError` a equivalência reside sob os trâmites do provedor em deter na sua posse o equivalente a essas chaves geradas em antecedência. Para salvaguarda frente a tentativas sem provimento ateste, antes das ocorrências se perfazerem mediante chamada direta utilizando-se do utilitário voltado a conferir `getClientCapabilities()`, para se guiar garantindo e confirmando as prerrogativas sob a modalidade da compatibilidade ao acionar vertentes interligadas a um estado focado e visível correspondente sem prejudicar indicadores sensíveis e volumes errôneos perante os contadores centrais.

### Qual contexto devo registrar junto com error.name para tornar as falhas do WebAuthn realmente depuráveis?

A fim de desvendar a amplitude da temática registrando os cenários na ocorrência dos obstáculos com a viabilidade associada às ações inerentes no modelo de intervenção atrelado ao registo dos trâmites perante a invocação efetuada nos mecanismos em conformidade sob a rubrica da origem do tempo despendido face às manifestações contadas a partir do decorrer exato da modalidade operatória imposta — bem como das sub-versões na origem atrelada ao aparelho central sem descurar o panorama subjacente sob o painel principal inerente no terminal do qual é exposta a manifestação no quadro de cruzamentos com pormenores inerentes na UI enquadrada num plano em híbrido e uma credencial representativa atrelada no campo com valências numa equivalência voltada a reunir todas inter-ligações partindo dos rastros provindos e acolhidos aos processos executáveis atrelados ao plano servidor perante o back-end associado de forma paralela. Revezes e deflexões com proveniência vinda nos canais oriundos em trâmites nos processos sob as recusas na validade da assinatura base aliando isso ainda sob atestados caducos provindos sem sucesso em desvendar e encontrar identificações registadas devem integrar códigos fixos delineados nas regras que gerem os campos sem permitir sobreposições difusas acopladas com a dimensão que atrela nas diretivas nativas nos navegadores adjacentes na sintaxe base e subjacente em basear esses modelos em formato inerente ao tipo voltado à denominação provinda sob origem no espetro `DOMException` dos canais provindos ao lado contíguo onde reside a base de dados em volta dos eventos originários. Esse enquadramento dotado das suas qualidades acoplado perante as interações em vista agrupa essas manifestações agrupando-as na categoria a providenciar mecanismos úteis com precisões infalíveis sem a dimensão aleatória subjacente baseando apenas as suposições e o cenário em deduções baseadas na tentativa.
