{"record":{"id":"647a4cf20d91461e","repo":"lapce/lapce","slug":"get-release-info-failed-647a4c","errorCode":null,"errorMessage":"get release info failed {}","messagePattern":"get release info failed (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lapce-app/src/update.rs","lineNumber":35,"sourceCode":"pub struct ReleaseAsset {\n    pub name: String,\n    pub browser_download_url: String,\n}\n\npub fn get_latest_release() -> Result<ReleaseInfo> {\n    let url = match meta::RELEASE {\n        meta::ReleaseType::Debug => {\n            return Err(anyhow!(\"no release for debug\"));\n        }\n        meta::ReleaseType::Nightly => {\n            \"https://api.github.com/repos/lapce/lapce/releases/tags/nightly\"\n        }\n        _ => \"https://api.github.com/repos/lapce/lapce/releases/latest\",\n    };\n\n    let resp = lapce_proxy::get_url(url, Some(\"Lapce\"))?;\n    if !resp.status().is_success() {\n        return Err(anyhow!(\"get release info failed {}\", resp.text()?));\n    }\n    let mut release: ReleaseInfo = serde_json::from_str(&resp.text()?)?;\n\n    release.version = match release.tag_name.as_str() {\n        \"nightly\" => format!(\n            \"{}+Nightly.{}\",\n            env!(\"CARGO_PKG_VERSION\"),\n            &release.target_commitish[..7]\n        ),\n        _ => release\n            .tag_name\n            .strip_prefix('v')\n            .unwrap_or(&release.tag_name)\n            .to_owned(),\n    };\n\n    Ok(release)\n}","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/lapce/lapce/blob/c9e4c33948033f10f003991a037d949a708eedf8/lapce-app/src/update.rs#L17-L53","documentation":"Raised by get_latest_release() in lapce-app/src/update.rs when the GitHub Releases API request completes at the transport level but returns a non-success HTTP status. The response body is interpolated into the message, so the real cause (rate limit, missing release, proxy error page) is visible in the '{}'. This is Lapce's own updater talking to api.github.com, not a third-party library error.","triggerScenarios":"Calling get_latest_release() with meta::RELEASE set to Nightly or a stable release, and the GET to https://api.github.com/repos/lapce/lapce/releases/{tags/nightly|latest} answering 403 (unauthenticated rate limit, 60 req/hr), 404 (tag or repo missing), 401, or 5xx. lapce_proxy::get_url itself succeeded (no '?' error), only resp.status().is_success() is false.","commonSituations":"Frequent update checks or CI environments exhausting the anonymous GitHub API rate limit; nightly tag temporarily unpublished during release automation; corporate proxies / SSL inspection returning HTML error pages with a 4xx/5xx status; GitHub outage.","solutions":["Read the '{}' body: 'API rate limit exceeded' means waiting until X-RateLimit-Reset (up to 1h for anonymous clients)","Verify the endpoint manually: curl -i https://api.github.com/repos/lapce/lapce/releases/latest","Retry with exponential backoff (30s, 2m) for transient 5xx/proxy failures","Route Lapce through a proxy that caches or authenticates GitHub API calls (lapce_proxy::get_url honors standard proxy env vars)","If the nightly tag is genuinely absent, wait for release CI to republish it"],"exampleFix":"// before\nlet resp = lapce_proxy::get_url(url, Some(\"Lapce\"))?;\nif !resp.status().is_success() {\n    return Err(anyhow!(\"get release info failed {}\", resp.text()?));\n}\n\n// after: keep the status code so callers can react to rate limits\nlet resp = lapce_proxy::get_url(url, Some(\"Lapce\"))?;\nlet status = resp.status();\nif !status.is_success() {\n    let body = resp.text().unwrap_or_default();\n    return Err(anyhow!(\n        \"get release info failed: HTTP {} — {}\",\n        status.as_u16(),\n        body\n    ));\n}","handlingStrategy":"retry","validationCode":"// Pre-flight: confirm the endpoint is reachable and not rate-limited before the real call\nlet resp = lapce_proxy::get_url(\"https://api.github.com/rate_limit\", Some(\"Lapce\"))?;\nif resp.status().as_u16() == 403 {\n    return Err(anyhow!(\"skip update check: GitHub API rate-limited\"));\n}","typeGuard":null,"tryCatchPattern":"let release = match get_latest_release() {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"get release info failed\") => {\n        // 403 rate-limit / 5xx are transient: back off and retry once or twice\n        std::thread::sleep(Duration::from_secs(30));\n        get_latest_release()?\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Cache release info instead of polling on every launch — anonymous GitHub API allows 60 requests/hour","Surface the embedded response body in logs so rate limits are diagnosed immediately","Respect proxy configuration so corporate networks don't inject error pages"],"tags":["network","http","github-api","updater","rust"],"backgroundTag":null,"analyzedSha":"c9e4c33948033f10f003991a037d949a708eedf8","analyzedAt":"2026-08-16T11:46:13.210Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}