{"record":{"id":"36f24d84bd4b94f2","repo":"atuinsh/atuin","slug":"invalid-login-details-36f24d","errorCode":null,"errorMessage":"invalid login details","messagePattern":"invalid login details","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"crates/atuin-client/src/auth.rs","lineNumber":208,"sourceCode":"        let client = self.authenticated_client()?;\n        let url = self.address.append_path(\"account/password\")?;\n\n        let resp = client\n            .patch(url)\n            .json(&ChangePasswordRequest {\n                current_password: current_password.to_string(),\n                new_password: new_password.to_string(),\n            })\n            .send()\n            .await?;\n\n        match resp.status().as_u16() {\n            200 => Ok(MutateResponse::Success),\n            401 => {\n                bail!(\"current password is incorrect\");\n            }\n            403 => {\n                bail!(\"invalid login details\");\n            }\n            _ => {\n                bail!(\"unknown error\");\n            }\n        }\n    }\n\n    async fn delete_account(\n        &self,\n        password: &str,\n        _totp_code: Option<&str>,\n    ) -> Result<MutateResponse> {\n        let client = self.authenticated_client()?;\n        let url = self.address.append([\"account\"])?;\n\n        let resp =\n            client.delete(url).json(&serde_json::json!({ \"password\": password })).send().await?;\n","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/atuinsh/atuin/blob/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin-client/src/auth.rs#L190-L226","documentation":"This bail fires when the `PATCH account/password` request returns HTTP 403. The client interprets 403 as 'the credentials you presented are not authorized for this account operation' — the login details (token/session vs. account) don't match. Unlike 401 (bad current password), 403 means authenticated but forbidden.","triggerScenarios":"Calling `change_password` with a session token that belongs to a different account than the password being changed, or the server explicitly forbids the operation for this authenticated identity.","commonSituations":"Mixing sessions after switching accounts on one machine; a server policy blocks password change for this account (e.g. managed/OAuth-linked accounts); stale config pointing at a different sync server than the one the session was issued by.","solutions":["Confirm the logged-in account matches the account you intend to change (`atuin status` / stored session identity)","Log in again to the correct account, then retry the password change","Check whether the account is managed/linked and disallows direct password changes on this server","Verify `sync_address` points at the server that issued your current session"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_forbidden_change(err: &Report) -> bool {\n    err.to_string() == \"invalid login details\"\n}","tryCatchPattern":"match auth_client.change_password(current, new, totp).await {\n    Ok(MutateResponse::Success) => println!(\"password updated\"),\n    Err(e) if e.to_string() == \"invalid login details\" => {\n        eprintln!(\"session not authorized for this account; re-login as the correct user\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Ensure you are logged in as the account you intend to modify","Re-login after switching accounts so the session matches the target","Check server/ACL policies if the account is managed or OAuth-linked","Keep sync_address consistent with the server that issued your session"],"tags":["http","authentication","forbidden","atuin"],"backgroundTag":"permission-denied","analyzedSha":"900007c48045867e7f44b0f9bc55ad9dbe99ee0d","analyzedAt":"2026-09-19T12:52:51.491Z","contentChangedAt":"2026-09-19T12:52:51.491Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}