{"record":{"id":"59340948a18402eb","repo":"nextauthjs/next-auth","slug":"failed-to-update-authenticator-counter-this-may-c","errorCode":null,"errorMessage":"Failed to update authenticator counter. This may cause future authentication attempts to fail. ${JSON.stringify({credentialID, oldCounter: authenticator.counter, newCounter: authenticationInfo.newCounter})}","messagePattern":"Failed to update authenticator counter\\. This may cause future authentication attempts to fail\\. (.+?)\\)\\}","errorType":"exception","errorClass":"AdapterError","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/utils/webauthn-utils.ts","lineNumber":277,"sourceCode":"\n  const { verified, authenticationInfo } = verification\n\n  // Make sure the response was verified\n  if (!verified) {\n    throw new WebAuthnVerificationError(\n      \"WebAuthn authentication response could not be verified\"\n    )\n  }\n\n  // Update authenticator counter\n  try {\n    const { newCounter } = authenticationInfo\n    await adapter.updateAuthenticatorCounter(\n      authenticator.credentialID,\n      newCounter\n    )\n  } catch (e: any) {\n    throw new AdapterError(\n      `Failed to update authenticator counter. This may cause future authentication attempts to fail. ${JSON.stringify(\n        {\n          credentialID,\n          oldCounter: authenticator.counter,\n          newCounter: authenticationInfo.newCounter,\n        }\n      )}`,\n      e\n    )\n  }\n\n  // Get the account and user\n  const account = await adapter.getAccount(\n    authenticator.providerAccountId,\n    provider.id\n  )\n  if (!account) {\n    throw new AuthError(","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/utils/webauthn-utils.ts#L259-L295","documentation":"The credential verification succeeded, but updating the authenticator's signature counter via adapter.updateAuthenticatorCounter failed. The library escalates it to an AdapterError with details because a stale counter can cause future assertions to be rejected as cloned authenticators.","triggerScenarios":"updateAuthenticatorCounter throws inside verifyAuthenticate — adapter not connected, DB write error, or a custom adapter that doesn't implement updateAuthenticatorCounter.","commonSituations":"Database connection pool exhausted or down at write time; custom adapter missing the updateAuthenticatorCounter method; schema migration removed the counter column; permissions preventing updates.","solutions":["Check database connectivity and adapter error logs for the root cause","Implement updateAuthenticatorCounter in your custom adapter if missing","Verify the Authenticator table still has a counter column in your schema","Re-run authentication once the adapter write path is healthy"],"exampleFix":"// before\n// adapter missing updateAuthenticatorCounter -> AdapterError\n// after\nasync updateAuthenticatorCounter(credentialID, counter) {\n  await db.authenticator.update({ where: { credentialID }, data: { counter } })\n}","handlingStrategy":"try-catch","validationCode":"if (typeof adapter.updateAuthenticatorCounter !== 'function') {\n  throw new Error('Adapter must implement updateAuthenticatorCounter')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await verifyAuthenticate(data)\n} catch (e) {\n  if (e instanceof AdapterError && e.message.includes('authenticator counter')) {\n    logger.error(e.message) // auth succeeded but counter stale; alert ops\n  } else { throw e }\n}","preventionTips":["Implement all AuthenticatorFramework adapter methods when writing custom adapters","Keep the counter column in your schema migrations","Watch database connectivity and pool health","Alert on this error since stale counters can block future logins"],"tags":["webauthn","adapter","database","counter"],"backgroundTag":"adapter-write-failed","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}