atuinsh/atuin · error
invalid login details
Error message
invalid login details
What it means
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.
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
Example fix
null
Defensive patterns
Strategy: try-catch
Type guard
fn is_forbidden_change(err: &Report) -> bool {
err.to_string() == "invalid login details"
} Try / catch
match auth_client.change_password(current, new, totp).await {
Ok(MutateResponse::Success) => println!("password updated"),
Err(e) if e.to_string() == "invalid login details" => {
eprintln!("session not authorized for this account; re-login as the correct user");
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19).
Data as JSON: /api/errors/36f24d84bd4b94f2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/atuin-client/src/auth.rs:208
let client = self.authenticated_client()?;
let url = self.address.append_path("account/password")?;
let resp = client
.patch(url)
.json(&ChangePasswordRequest {
current_password: current_password.to_string(),
new_password: new_password.to_string(),
})
.send()
.await?;
match resp.status().as_u16() {
200 => Ok(MutateResponse::Success),
401 => {
bail!("current password is incorrect");
}
403 => {
bail!("invalid login details");
}
_ => {
bail!("unknown error");
}
}
}
async fn delete_account(
&self,
password: &str,
_totp_code: Option<&str>,
) -> Result<MutateResponse> {
let client = self.authenticated_client()?;
let url = self.address.append(["account"])?;
let resp =
client.delete(url).json(&serde_json::json!({ "password": password })).send().await?;
View on GitHub (pinned to 900007c480)