{"record":{"id":"bd40b2a486c089f3","repo":"moghtech/komodo","slug":"service-users-cannot-add-additional-login-methods","errorCode":null,"errorMessage":"Service Users cannot add additional login methods","messagePattern":"Service Users cannot add additional login methods","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"lib/database/src/lib.rs","lineNumber":138,"sourceCode":"    password: &str,\n  ) -> anyhow::Result<()> {\n    if password.is_empty() {\n      return Err(anyhow!(\"Password cannot be empty.\"));\n    }\n    let hashed_password =\n      hash_password(password).context(\"Failed to hash password\")?;\n    self.set_user_hashed_password(user, hashed_password).await\n  }\n\n  /// Updates a user's password using a DB call.\n  pub async fn set_user_hashed_password(\n    &self,\n    user: &User,\n    hashed_password: String,\n  ) -> anyhow::Result<()> {\n    let update = match user.config {\n      UserConfig::Service { .. } => {\n        return Err(anyhow!(\n          \"Service Users cannot add additional login methods\"\n        ));\n      }\n      // Update a primary 'Local' user's password directly.\n      UserConfig::Local { .. } => {\n        doc! {\n          \"$set\": {\n            \"config.data.password\": hashed_password\n          }\n        }\n      }\n      // Update User with Local password as an entry in 'additional_logins'\n      _ => {\n        let bson = to_bson(&UserConfig::Local {\n          password: hashed_password,\n        })\n        .context(\"Failed to serialize login method to bson\")?;\n        doc! {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/moghtech/komodo/blob/780ac68b992094a9fccd5fffb760e0c84fd3c3d1/lib/database/src/lib.rs#L120-L156","documentation":"set_user_hashed_password inspects the user's UserConfig before building the update document: if the user is a Service user (machine account), no password login method may be attached to it, so the update is rejected with this error. It is a business-rule guard protecting the invariant that Service accounts authenticate via other means, not passwords.","triggerScenarios":"Calling set_user_hashed_password (directly or via set_user_password) on a User whose config is UserConfig::Service.","commonSituations":"Admin password-reset UI iterating over all users including service accounts; scripts that reset passwords for automation users; mixing up a service account's ID with a human user's ID.","solutions":["Only call password updates for users with UserConfig::Local","Filter service users out in admin reset flows (match user.config before calling)","If the account should have a password, it was mis-provisioned — recreate it as a Local user","Use the service account's intended credential mechanism instead of a password"],"exampleFix":"// before\nfor user in users { db.set_user_password(&user, tmp_pw).await?; }\n// after\nfor user in users {\n  if matches!(user.config, UserConfig::Local { .. }) {\n    db.set_user_password(&user, tmp_pw).await?;\n  }\n}","handlingStrategy":"type-guard","validationCode":"fn can_set_password(user: &User) -> bool {\n  matches!(user.config, UserConfig::Local { .. })\n}","typeGuard":"fn is_local_user(user: &User) -> bool {\n  matches!(user.config, UserConfig::Local { .. })\n}","tryCatchPattern":"match db.set_user_password(&user, &pw).await {\n  Err(e) if e.to_string().contains(\"Service Users cannot\") => {\n    log::info!(\"skipped password reset for service account {}\", user.id);\n    Ok(())\n  }\n  other => other,\n}","preventionTips":["Check user.config before any password-related call","Exclude UserConfig::Service accounts from password-reset UIs and bulk scripts","Track service accounts separately from human accounts in admin tooling"],"tags":["authentication","user-management","business-rule","service-account"],"backgroundTag":"unsupported-operation","analyzedSha":"780ac68b992094a9fccd5fffb760e0c84fd3c3d1","analyzedAt":"2026-09-08T10:02:44.861Z","contentChangedAt":"2026-09-08T10:02:44.861Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}