{"record":{"id":"d16491a6ccfec245","repo":"gitbutlerapp/gitbutler","slug":"api-returned-version-but-requested-version","errorCode":null,"errorMessage":"API returned version {} but requested version {}","messagePattern":"API returned version (.+?) but requested version (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/release.rs","lineNumber":84,"sourceCode":"    // Validate the effective URL after following redirects\n    // This protects against malicious redirects to untrusted domains or insecure protocols\n    let effective_url = easy\n        .effective_url()\n        .context(\"Failed to get effective URL\")?\n        .ok_or_else(|| anyhow!(\"Effective URL is missing\"))?;\n\n    validate_api_url(effective_url).with_context(|| {\n        format!(\"Release API was redirected to an untrusted URL: {effective_url}\")\n    })?;\n\n    let release: Release =\n        serde_json::from_slice(&response_data).context(\"Failed to parse release information\")?;\n\n    // Verify we got the version we requested (skip check for nightly)\n    if let crate::config::VersionRequest::Specific(ref requested) = config.version_request\n        && release.version != requested.as_str()\n    {\n        bail!(\n            \"API returned version {} but requested version {}\",\n            release.version,\n            requested\n        );\n    }\n\n    Ok(release)\n}\n\n/// Common URL validation logic for GitButler domains.\n///\n/// Validates HTTPS protocol, parses URL, and checks the host against a predicate.\nfn validate_gitbutler_url(\n    url: &str,\n    url_type: &str,\n    is_host_valid: impl Fn(&str) -> bool,\n) -> Result<()> {\n    // Only allow HTTPS URLs","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/release.rs#L66-L102","documentation":"After parsing the release JSON, fetch_release verifies that for a Specific version request the API-returned release.version equals the requested string. A mismatch indicates the resolved release differs from what was asked, so the installer refuses to avoid installing the wrong version.","triggerScenarios":"The API redirected or resolved the request to a different release than requested (e.g. version moved, alias endpoint, or server returning latest instead of the specific tag); or the version string format differs (e.g. \"1.2.3\" vs \"v1.2.3\").","commonSituations":"Requesting \"v1.2.3\" when releases are tagged \"1.2.3\" (or vice versa), server-side aliasing to latest, cache serving a different release metadata,上游 API behavior changes.","solutions":["Compare the requested string against the actual release tag format (leading 'v', suffixes)","Request the exact tag as published by the API","Clear any intermediary cache/proxy serving stale release metadata","Update the installer — server-side endpoint behavior may have changed"],"exampleFix":"// before\ninstall_with_version(\"v1.2.3\")?;\n// after\ninstall_with_version(\"1.2.3\")?; // match the tag exactly as published","handlingStrategy":"validation","validationCode":"// normalize and compare version strings before requesting\nlet requested = version.trim_start_matches('v');\nassert_eq!(requested, expected_tag, \"version must match published tag exactly\");","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"API returned version\") => {\n        // compare requested vs returned; fix version string format and retry\n    }\n    other => other?,\n}","preventionTips":["Always use the exact tag string as published (watch for leading 'v')","Log requested vs returned versions for diagnosis","Beware of endpoints that alias to latest","Keep the installer updated for upstream API changes"],"tags":["api","versioning","validation","release"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}