atuinsh/atuin · error
invalid credentials
Error message
invalid credentials
What it means
In `HubAuthClient::login`, an HTTP 401 (UNAUTHORIZED) response is mapped to this fixed bail. 401 means the supplied username/password combination failed authentication on the Hub. The client deliberately does not parse the body and reports 'invalid credentials'.
Solutions
- Re-enter username and password carefully, checking for autocorrect/whitespace issues
- Verify the account exists on Atuin Hub (register first if not) and that you're logging into the right service
- Reset the password via the Hub web UI if it may have changed
- If 2FA is enabled on the account, run login again and provide the TOTP code when prompted
- Confirm you're not mixing credentials from a self-hosted server with the public Hub
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
// Basic client-side sanity checks before hitting the Hub
if username.trim().is_empty() || password.is_empty() {
bail!("username and password must be non-empty");
}
// Optionally verify credentials independently before login Type guard
fn is_invalid_credentials(err: &Report) -> bool {
err.to_string() == "invalid credentials"
} Try / catch
match hub.login(username, password, totp).await {
Ok(AuthResponse::Success { .. }) => println!("logged in"),
Err(e) if e.to_string() == "invalid credentials" => {
eprintln!("check username/password; reset via Hub web UI if forgotten");
}
Ok(AuthResponse::TwoFactorRequired) => { /* collect TOTP and retry */ }
Err(e) => return Err(e),
} Prevention
- Double-check username/password for typos, casing, and stray whitespace
- Keep credentials current — re-login after any password change elsewhere
- Confirm the account exists on the target service (Hub vs self-hosted)
- Enable and supply 2FA codes to avoid ambiguous auth failures
When it happens
Trigger: POST `api/v0/login` with a wrong username, wrong password, or a username that doesn't exist (server answers 401 for both to avoid user enumeration).
Common situations: Typo'd username or password in `atuin login`; credentials from a password manager out of date after a recent change; attempting login on Atuin Hub with a local-only/self-hosted account; case-sensitivity mistakes in username.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- {}
- Hub login failed with status
- current password is incorrect
- invalid login details
- password is incorrect
AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19).
Data as JSON: /api/errors/586b576efa2de545.
Report an issue: GitHub.
Appendix: source
Thrown at crates/atuin-client/src/auth.rs:316
if status.is_success() {
let login: LoginResponse = resp.json().await?;
return Ok(AuthResponse::Success {
session: login.session,
auth_type: login.auth,
});
}
if status == StatusCode::FORBIDDEN
&& let Ok(err) = resp.json::<HubErrorResponse>().await
{
if err.code.as_deref() == Some("2fa_required") {
return Ok(AuthResponse::TwoFactorRequired);
}
bail!("{}", err.reason);
}
if status == StatusCode::UNAUTHORIZED {
bail!("invalid credentials");
}
bail!("Hub login failed with status {status}");
}
async fn register(&self, username: &str, email: &str, password: &str) -> Result<AuthResponse> {
let url = self.address.append_path("api/v0/register")?;
let client = reqwest::Client::new();
let resp = client
.post(url)
.header(USER_AGENT, APP_USER_AGENT)
.header(ATUIN_HEADER_VERSION, ATUIN_CARGO_VERSION)
.json(&serde_json::json!({
"email": email,
"username": username,
"password": password,
}))View on GitHub (pinned to 900007c480)