atuinsh/atuin · error

Could not login due to version mismatch

Error message

Could not login due to version mismatch

What it means

After a login POST, `ensure_version` verifies the server version from the response headers. Login is aborted when the server is too old (or too new) for the client to interoperate with, preventing a partially working session.

Solutions

  1. Upgrade the sync server to at least the client's major/minor version
  2. Or downgrade the client to match the server
  3. Verify the server reports a version header at all (curl the login endpoint)
  4. Keep client and server updated together
Defensive patterns

Strategy: validation

Validate before calling

let server_ver = fetch_server_version(&address).await?;
if semver::Version::parse(&server_ver)?.major < ATUIN_VERSION.major {
    eprintln!("server too old for this client; upgrade server first");
    return Ok(());
}

Try / catch

match login(&client, &address, req).await {
    Err(e) if e.to_string().contains("version mismatch") => {
        // guide user to upgrade server or downgrade client
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: Running `atuin login` against a sync server whose version header fails the client's compatibility check.

Common situations: Self-hosted Atuin server lagging behind a recently updated client; enterprise deployments pinned to old releases.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/eaca4794094cbcaf. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-client/src/api_client.rs:177

}

#[instrument(level = "trace", skip_all, err)]
pub async fn login(
    address: &Url,
    req: LoginRequest,
    extra_headers: &HashMap<String, String>,
) -> Result<LoginResponse> {
    let url = address.append(["login"])?;
    let client = client_builder(extra_headers).build()?;

    let mut headers = extra_headers_map(extra_headers)?;
    headers.insert(USER_AGENT, APP_USER_AGENT.parse()?);

    let resp = client.post(url).headers(headers).json(&req).send().await?;
    let resp = handle_resp_error(resp).await?;

    if !ensure_version(&resp)? {
        bail!("Could not login due to version mismatch");
    }

    let session = resp.json::<LoginResponse>().await?;
    Ok(session)
}

#[cfg(feature = "check-update")]
#[instrument(level = "trace", skip_all, err)]
pub async fn latest_version() -> Result<Version> {
    use atuin_domain::api::IndexResponse;

    let url = crate::settings::DEFAULT_SYNC_URL.clone();
    let client = reqwest::Client::new();

    let resp = client.get(url).header(USER_AGENT, APP_USER_AGENT).send().await?;
    let resp = handle_resp_error(resp).await?;

    let index = resp.json::<IndexResponse>().await?;

View on GitHub (pinned to 900007c480)