{"record":{"id":"6153cf1f496e7e03","repo":"atuinsh/atuin","slug":"failed-to-parse-server-version","errorCode":null,"errorMessage":"failed to parse server version: {:?}","messagePattern":"failed to parse server version: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-client/src/api_client.rs","lineNumber":208,"sourceCode":"    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?;\n    let version = Version::parse(index.version.as_str())?;\n\n    Ok(version)\n}\n\npub fn ensure_version(response: &Response) -> Result<bool> {\n    let version = response.headers().get(ATUIN_HEADER_VERSION);\n\n    let version = if let Some(version) = version {\n        match version.to_str() {\n            Ok(v) => Version::parse(v),\n            Err(e) => {\n                bail!(\"failed to parse server version: {:?}\", e);\n            }\n        }\n    } else {\n        bail!(\"Server not reporting its version: it is either too old or unhealthy\");\n    }?;\n\n    // If the client is newer than the server\n    if version.major < ATUIN_VERSION.major {\n        println!(\n            \"Atuin version mismatch! In order to successfully sync, the server needs to run a \\\n             newer version of Atuin\"\n        );\n        println!(\"Client: {ATUIN_CARGO_VERSION}\");\n        println!(\"Server: {version}\");\n\n        return Ok(false);\n    }\n","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/atuinsh/atuin/blob/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin-client/src/api_client.rs#L190-L226","documentation":"`ensure_version` reads the `x-atuin-version` header from a server response and parses it as a semver Version. If the header value is not valid UTF-8 (or the semver parse fails) the client bails with the underlying header conversion error debug-printed.","triggerScenarios":"Any API call routed through `ensure_version` (register, login, record_status) where the version header exists but its bytes are not valid UTF-8 or not valid semver.","commonSituations":"A reverse proxy injecting a malformed x-atuin-version header, a non-Atuin service on the sync URL, or a corrupted/modified server build.","solutions":["Inspect the header: `curl -sD - <sync-url> | grep -i atuin-version`","Fix or remove the proxy rule that rewrites the header","Point `sync_address` at a genuine Atuin server","If parsing semver fails, upgrade the server to a version emitting valid semver"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// pre-flight: confirm the server emits a parseable semver version header\nlet resp = reqwest::get(format!(\"{sync_address}/health\")).await?;\nlet v = resp.headers().get(\"x-atuin-version\")\n    .and_then(|h| h.to_str().ok())\n    .ok_or(\"no version header\")?;\nsemver::Version::parse(v)?; // fails fast here, not mid-login","typeGuard":"fn valid_version_header(resp: &reqwest::Response) -> Option<semver::Version> {\n    resp.headers().get(\"x-atuin-version\")\n        .and_then(|h| h.to_str().ok())\n        .and_then(|v| semver::Version::parse(v).ok())\n}","tryCatchPattern":null,"preventionTips":["Check proxies don't rewrite custom headers","Point sync_address only at genuine Atuin servers","Validate server health before scripted register/login"],"tags":["http","headers","versioning","semver"],"backgroundTag":"unexpected-response-shape","analyzedSha":"900007c48045867e7f44b0f9bc55ad9dbe99ee0d","analyzedAt":"2026-09-19T12:52:51.491Z","contentChangedAt":"2026-09-19T12:52:51.491Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}