BigPizzaV3/CodexPlusPlus · error · anyhow::Error

下载安装包失败:{error}

Error message

下载安装包失败:{error}

What it means

perform_update downloads the asset via update_http_client()?.get(url).send().await; if reqwest cannot complete the request at all, the reqwest error is wrapped as "下载安装包失败:{error}" and logged to the diagnostic log under update.download.failed. This is transport-level failure (DNS, TCP connect, TLS handshake, proxy error, request timeout), distinct from the later HTTP-status and body-read stages.

Source

Thrown at crates/codex-plus-core/src/update.rs:222

        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("没有可下载的 Release asset"))?;
    let _ = crate::diagnostic_log::append_diagnostic_log(
        "update.perform.start",
        json!({
            "version": release.version,
            "assetName": release.asset_name,
            "assetUrl": url,
            "downloadTimeoutSeconds": UPDATE_DOWNLOAD_TIMEOUT.as_secs()
        }),
    );
    let response = match update_http_client()?.get(url).send().await {
        Ok(response) => response,
        Err(error) => {
            let _ = crate::diagnostic_log::append_diagnostic_log(
                "update.download.failed",
                json!({ "version": release.version, "assetName": release.asset_name, "error": error.to_string() }),
            );
            return Err(anyhow::anyhow!("下载安装包失败:{error}"));
        }
    };
    let response = match response.error_for_status() {
        Ok(response) => response,
        Err(error) => {
            let _ = crate::diagnostic_log::append_diagnostic_log(
                "update.download.bad_status",
                json!({ "version": release.version, "assetName": release.asset_name, "error": error.to_string() }),
            );
            return Err(anyhow::anyhow!("下载安装包失败:{error}"));
        }
    };
    let bytes = match response.bytes().await {
        Ok(bytes) => bytes,
        Err(error) => {
            let _ = crate::diagnostic_log::append_diagnostic_log(
                "update.download.body_failed",
                json!({ "version": release.version, "assetName": release.asset_name, "error": error.to_string() }),

View on GitHub (pinned to 1f431ae49b)

Solutions

  1. Check basic connectivity to the asset URL (curl -I <asset_url>)
  2. Fix or unset HTTP_PROXY/HTTPS_PROXY/ALL_PROXY if the proxy is unreachable
  3. Retry after restoring network/DNS
  4. If you build from source and consistently hit the timeout, raise UPDATE_DOWNLOAD_TIMEOUT in update.rs

Example fix

// before
let install = perform_update(&release, &dir).await?;

// after (bounded retry for transport errors)
let mut last_err = None;
for attempt in 0..3u32 {
    match perform_update(&release, &dir).await {
        Ok(install) => return Ok(install),
        Err(e) if e.to_string().contains("下载安装包失败") && attempt < 2 => {
            tokio::time::sleep(std::time::Duration::from_secs(1 << attempt)).await;
            last_err = Some(e);
        }
        Err(e) => return Err(e),
    }
}
Err(last_err.unwrap())
Defensive patterns

Strategy: retry

Try / catch

for attempt in 0..3u32 {
    match perform_update(&release, &dir).await {
        Ok(install) => return Ok(install),
        Err(e) if e.to_string().contains("下载安装包失败") && attempt < 2 => {
            tokio::time::sleep(std::time::Duration::from_secs(1 << attempt)).await;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Machine offline or DNS broken when the update starts; HTTPS_PROXY/ALL_PROXY pointing at a dead proxy; TLS interception rejecting the CDN certificate; the connection phase exceeding UPDATE_DOWNLOAD_TIMEOUT.

Common situations: Corporate networks blocking GitHub Releases / object-storage CDNs; VPN split-tunneling dropping the CDN domain; containers without proxy env vars configured; captive portals.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16). Data as JSON: /api/errors/11fa83886b0370d4. Report an issue: GitHub.