{"record":{"id":"f2d25adfdbc06307","repo":"zeroclaw-labs/zeroclaw","slug":"no-credentials-found-for-user-user-id","errorCode":null,"errorMessage":"No credentials found for user '{user_id}'","messagePattern":"No credentials found for user '(.+?)'","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/security/webauthn.rs","lineNumber":503,"sourceCode":"    }\n\n    /// List all credentials for a user.\n    pub fn list_credentials(&self, user_id: &str) -> Result<Vec<WebAuthnCredential>> {\n        self.load_credentials_for_user(user_id)\n    }\n\n    /// Remove a credential by ID.\n    pub fn remove_credential(&self, user_id: &str, credential_id: &str) -> Result<()> {\n        let mut all = self.load_all_credentials()?;\n        if let Some(user_creds) = all.get_mut(user_id) {\n            let before = user_creds.len();\n            user_creds.retain(|c| c.credential_id != credential_id);\n            anyhow::ensure!(\n                user_creds.len() < before,\n                \"Credential '{credential_id}' not found for user '{user_id}'\"\n            );\n        } else {\n            anyhow::bail!(\"No credentials found for user '{user_id}'\");\n        }\n        self.save_all_credentials(&all)\n    }\n\n    // ── Private helpers ─────────────────────────────────────────\n\n    fn generate_challenge(&self) -> Result<String> {\n        let mut buf = [0u8; CHALLENGE_LEN];\n        self.rng.fill(&mut buf).map_err(|_| {\n            ::zeroclaw_log::record!(\n                ERROR,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Failure),\n                \"webauthn challenge: RNG fill failed\"\n            );\n            anyhow::Error::msg(\"Failed to generate random challenge\")\n        })?;\n        Ok(URL_SAFE_NO_PAD.encode(buf))","sourceCodeStart":485,"sourceCodeEnd":521,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/security/webauthn.rs#L485-L521","documentation":"remove_credential loads the whole credential store and looks up user_id; when the user has no entry at all, it bails with 'No credentials found' (webauthn.rs:502-504). This is distinct from the sibling error 'Credential ... not found' (webauthn.rs:498-501), which fires when the user exists but that credential_id does not.","triggerScenarios":"remove_credential(user_id, credential_id) where the user never enrolled a WebAuthn credential, enrolled under a different user_id (case or prefix mismatch), or the credential store file was reset.","commonSituations":"Admin UI deletes by email while enrollment stored a UUID; the credentials JSON store was recreated after a wipe; double-submit after the first delete already removed the user's last credential.","solutions":["Verify the user_id matches exactly what enrollment used — list_credentials(user_id) shows what is stored","If your delete flow should be idempotent, treat 'no credentials / not found' as success instead of an error","Check that the credentials store path points to the same store used during registration"],"exampleFix":"// before\nmanager.remove_credential(&user_id, &credential_id)?;\n\n// after: idempotent delete\nlet creds = manager.list_credentials(&user_id)?;\nif creds.iter().any(|c| c.credential_id == credential_id) {\n    manager.remove_credential(&user_id, &credential_id)?;\n}\nOk(())","handlingStrategy":"validation","validationCode":"let creds = manager.list_credentials(&user_id)?;\nif creds.iter().any(|c| c.credential_id == credential_id) {\n    manager.remove_credential(&user_id, &credential_id)?;\n}\n// else: nothing to delete — treat as success","typeGuard":null,"tryCatchPattern":"If the pre-check is skipped, catch the error and treat both 'No credentials found' and 'not found for user' as idempotent success (or 404 in an admin API), logging the mismatched user_id for audit.","preventionTips":["Use one canonical user_id format from enrollment through deletion","Build delete UIs from list_credentials output so stale entries cannot be submitted","Make credential deletion idempotent in the API layer"],"tags":["webauthn","credentials","not-found","rust"],"backgroundTag":"webauthn-credential-not-found","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}