zeroclaw-labs/zeroclaw · warning
Credential '{credential_id}' not found for user '{user_id}'
Error message
Credential '{credential_id}' not found for user '{user_id}' What it means
remove_credential loads all stored credentials, finds the user's list, and retains everything not matching the given credential_id. If the retain left the list unchanged (the ID was not present), the removal failed and the error names the credential and user. A missing user list raises a separate error.
Source
Thrown at crates/zeroclaw-runtime/src/security/webauthn.rs:498
cred.sign_count = new_count;
}
self.save_all_credentials(&all_credentials)?;
Ok(())
}
/// List all credentials for a user.
pub fn list_credentials(&self, user_id: &str) -> Result<Vec<WebAuthnCredential>> {
self.load_credentials_for_user(user_id)
}
/// Remove a credential by ID.
pub fn remove_credential(&self, user_id: &str, credential_id: &str) -> Result<()> {
let mut all = self.load_all_credentials()?;
if let Some(user_creds) = all.get_mut(user_id) {
let before = user_creds.len();
user_creds.retain(|c| c.credential_id != credential_id);
anyhow::ensure!(
user_creds.len() < before,
"Credential '{credential_id}' not found for user '{user_id}'"
);
} else {
anyhow::bail!("No credentials found for user '{user_id}'");
}
self.save_all_credentials(&all)
}
// ── Private helpers ─────────────────────────────────────────
fn generate_challenge(&self) -> Result<String> {
let mut buf = [0u8; CHALLENGE_LEN];
self.rng.fill(&mut buf).map_err(|_| {
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure),View on GitHub (pinned to 88bb9c8533)
Solutions
- Refresh the credential list after any delete and before the next one
- Treat delete-not-found as success (idempotent delete) in the calling UI or wrapper
- Pass the credential_id exactly as returned by the list/registration API, unmodified
Defensive patterns
Strategy: validation
Validate before calling
// idempotent delete: only call remove_credential when present
let creds = service.list_credentials(user_id)?;
if creds.iter().any(|c| c.credential_id == cred_id) {
service.remove_credential(user_id, cred_id)?;
}
Ok(()) Try / catch
catch the not-found message and return success (idempotent delete semantics) or 404 to let the UI refresh its list — do not surface it as an unexpected error
Prevention
- Refresh the credential list after every mutation before enabling the next delete action
- Disable delete buttons after first click to prevent double submits
- Pass credential IDs through unmodified from API responses
When it happens
Trigger: Deleting a credential that was already removed (double-click, retrying a successful delete); an ID with different encoding or whitespace than stored; a UI list that is stale after another session removed the credential.
Common situations: Dashboard delete buttons firing twice; retry-after-timeout resubmits; multiple browser tabs both managing credentials; IDs copied with altered case or padding.
Related errors
- No credentials found for user '{user_id}'
- Unable to extract public key from attestation object ({} byt
- Unsupported COSE key format (expected uncompressed P-256, go
- Expected type 'webauthn.create', got '{cd_type}'
- Challenge mismatch in registration response
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/c1aa304535241067.
Report an issue: GitHub.