{"record":{"id":"edcd600969cbda73","repo":"zeroclaw-labs/zeroclaw","slug":"no-registered-credentials-for-user-user-id","errorCode":null,"errorMessage":"No registered credentials for user '{user_id}'","messagePattern":"No registered credentials for user '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":400,"severity":"error","filePath":"crates/zeroclaw-runtime/src/security/webauthn.rs","lineNumber":348,"sourceCode":"            algorithm: COSE_ALG_ES256,\n            user_id: reg_state.user_id.clone(),\n        };\n\n        // 4. Store the credential\n        self.store_credential(&credential)?;\n\n        Ok(credential)\n    }\n\n    /// Begin a WebAuthn authentication ceremony.\n    /// Returns the options to send to the browser and the server-side state\n    /// to keep until `finish_authentication` is called.\n    pub fn start_authentication(\n        &self,\n        user_id: &str,\n    ) -> Result<(RequestChallengeResponse, AuthenticationState)> {\n        let credentials = self.load_credentials_for_user(user_id)?;\n        anyhow::ensure!(\n            !credentials.is_empty(),\n            \"No registered credentials for user '{user_id}'\"\n        );\n\n        let challenge = self.generate_challenge()?;\n\n        let allow: Vec<CredentialDescriptor> = credentials\n            .iter()\n            .map(|c| CredentialDescriptor {\n                type_: \"public-key\".into(),\n                id: c.credential_id.clone(),\n            })\n            .collect();\n\n        let allowed_ids: Vec<String> = credentials\n            .iter()\n            .map(|c| c.credential_id.clone())\n            .collect();","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/security/webauthn.rs#L330-L366","documentation":"start_authentication loads all credentials stored for the user and requires at least one before building allowCredentials and issuing a challenge. If none exist for that user_id, authentication cannot proceed and the error names the user.","triggerScenarios":"User never completed registration; their credentials were removed via remove_credential; user_id differs from the one used at registration (different ID namespace, casing, or email vs internal ID); the credential store path pointing at an empty or wrong location.","commonSituations":"Frontend routing users to login before signup completed; identity mapping bugs between the app's user table and the WebAuthn store; users who deleted all their passkeys and must re-register; fresh environments with an empty credentials store.","solutions":["Route the user through registration (create a credential) before starting authentication","Verify the user_id passed in is byte-identical to the one used at registration time","Check the credentials store configuration (path/file) points where registrations are actually written"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// route users without credentials to registration before starting auth\nconst hasCredentials = await fetch(`/webauthn/credentials?user=${encodeURIComponent(userId)}`)\n  .then(r => r.json()).then(j => j.credentials.length > 0);\nif (!hasCredentials) { window.location = '/register'; }","typeGuard":null,"tryCatchPattern":"catch the no-credentials error at the auth-start handler and return 404 or a 'registration-required' code so the frontend can redirect instead of showing a generic failure","preventionTips":["Track a hasPasskey flag in the app's user record and gate the login UI on it","Use one canonical user_id mapping everywhere (same casing and namespace) at registration and login","After deleting a user's last credential, mark them as needing re-registration"],"tags":["webauthn","authentication","user-management","rust"],"backgroundTag":"webauthn-no-credentials-registered","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}