atuinsh/atuin · error

Could not login due to version mismatch

Error message

Could not login due to version mismatch

What it means

Like registration, `login` verifies the server version header after posting credentials. If `ensure_version` fails (server too old or version negotiation fails), login is refused with this message because the old server cannot produce a compatible session.

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 c0c717ab04)

Solutions

  1. Upgrade the sync server to at least the client's major version
  2. Ensure reverse proxies do not strip the `x-atuin-version` header
  3. Pin/downgrade the client temporarily if the server cannot be upgraded

Example fix

// before
atuin login -u alice   # server v17, client v18
// after
# upgrade server to v18 first, then:
atuin login -u alice
Defensive patterns

Strategy: validation

Validate before calling

// preflight login version check
let resp = client.get(format!("{address}/health")).send().await?;
let v = resp.headers().get("x-atuin-version").and_then(|v| v.to_str().ok());
let ok = v.map(|v| Version::parse(v).map(|sv| sv.major >= ATUIN_VERSION.major).unwrap_or(false));
if ok != Some(true) { eprintln!("server too old for this client"); return Ok(()); }

Try / catch

match login(...).await {
    Err(e) if e.to_string().contains("version mismatch") => {
        eprintln!("upgrade the sync server (or downgrade the client) and retry");
    }
    other => other?,
}

Prevention

When it happens

Trigger: `atuin login` against a sync server whose reported version is older than the client's major version, so `ensure_version` returns false

Common situations: Self-hosted server lagging behind a breaking client release; corporate proxy or cached old server image

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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