{"record":{"id":"eaca4794094cbcaf","repo":"atuinsh/atuin","slug":"could-not-login-due-to-version-mismatch","errorCode":null,"errorMessage":"Could not login due to version mismatch","messagePattern":"Could not login due to version mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-client/src/api_client.rs","lineNumber":177,"sourceCode":"}\n\n#[instrument(level = \"trace\", skip_all, err)]\npub async fn login(\n    address: &Url,\n    req: LoginRequest,\n    extra_headers: &HashMap<String, String>,\n) -> Result<LoginResponse> {\n    let url = address.append([\"login\"])?;\n    let client = client_builder(extra_headers).build()?;\n\n    let mut headers = extra_headers_map(extra_headers)?;\n    headers.insert(USER_AGENT, APP_USER_AGENT.parse()?);\n\n    let resp = client.post(url).headers(headers).json(&req).send().await?;\n    let resp = handle_resp_error(resp).await?;\n\n    if !ensure_version(&resp)? {\n        bail!(\"Could not login due to version mismatch\");\n    }\n\n    let session = resp.json::<LoginResponse>().await?;\n    Ok(session)\n}\n\n#[cfg(feature = \"check-update\")]\n#[instrument(level = \"trace\", skip_all, err)]\npub async fn latest_version() -> Result<Version> {\n    use atuin_domain::api::IndexResponse;\n\n    let url = crate::settings::DEFAULT_SYNC_URL.clone();\n    let client = reqwest::Client::new();\n\n    let resp = client.get(url).header(USER_AGENT, APP_USER_AGENT).send().await?;\n    let resp = handle_resp_error(resp).await?;\n\n    let index = resp.json::<IndexResponse>().await?;","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/atuinsh/atuin/blob/c0c717ab04c881764bcad4b3d169a507e2432643/crates/atuin-client/src/api_client.rs#L159-L195","documentation":"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.","triggerScenarios":"`atuin login` against a sync server whose reported version is older than the client's major version, so `ensure_version` returns false","commonSituations":"Self-hosted server lagging behind a breaking client release; corporate proxy or cached old server image","solutions":["Upgrade the sync server to at least the client's major version","Ensure reverse proxies do not strip the `x-atuin-version` header","Pin/downgrade the client temporarily if the server cannot be upgraded"],"exampleFix":"// before\natuin login -u alice   # server v17, client v18\n// after\n# upgrade server to v18 first, then:\natuin login -u alice","handlingStrategy":"validation","validationCode":"// preflight login version check\nlet resp = client.get(format!(\"{address}/health\")).send().await?;\nlet v = resp.headers().get(\"x-atuin-version\").and_then(|v| v.to_str().ok());\nlet ok = v.map(|v| Version::parse(v).map(|sv| sv.major >= ATUIN_VERSION.major).unwrap_or(false));\nif ok != Some(true) { eprintln!(\"server too old for this client\"); return Ok(()); }","typeGuard":null,"tryCatchPattern":"match login(...).await {\n    Err(e) if e.to_string().contains(\"version mismatch\") => {\n        eprintln!(\"upgrade the sync server (or downgrade the client) and retry\");\n    }\n    other => other?,\n}","preventionTips":["Track server releases alongside client releases","Test login against staging after server upgrades","Ensure proxies forward x-atuin-version"],"tags":["version-mismatch","sync","login"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"c0c717ab04c881764bcad4b3d169a507e2432643","analyzedAt":"2026-09-12T07:40:01.341Z","contentChangedAt":"2026-09-12T07:40:01.341Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}