gitbutlerapp/gitbutler · warning · anyhow::Error

Server returned error: {e}

Error message

Server returned error: {e}

What it means

The update server answered, but error_for_status() converted the response into an error because the HTTP status was non-success (4xx/5xx). The message includes the status code and URL — e.g. 401/403 for auth token issues, 5xx for server-side problems.

Source

Thrown at crates/but-update/src/check.rs:127

        .build()?;

    let url = url_override.unwrap_or(UPDATES_CHECK_URL).to_string();

    let result = std::thread::spawn(move || -> anyhow::Result<CheckUpdateStatus> {
        let runtime = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .map_err(|e| anyhow::anyhow!("Failed to create runtime: {e}"))?;

        runtime.block_on(async {
            let response = client
                .post(url)
                .json(&request_body)
                .send()
                .await
                .map_err(|e| anyhow::anyhow!("Request failed: {e}"))?
                .error_for_status()
                .map_err(|e| anyhow::anyhow!("Server returned error: {e}"))?;

            let update_info = response
                .json::<CheckUpdateStatus>()
                .await
                .map_err(|e| anyhow::anyhow!("Failed to parse response: {e}"))?;

            Ok(update_info)
        })
    })
    .join()
    .map_err(|_| anyhow::anyhow!("Update check thread panicked"))?;

    // Save to cache (convert to but_db types)
    if let Ok(status) = &result {
        let now = chrono::Utc::now();

        // Get existing cache to preserve suppression
        let existing = trans.update_check().get();

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Read the embedded status code in the error text to classify (4xx = request/auth problem, 5xx = server-side)
  2. For 401/403, verify the build's gitbutler_access_token secret is present/valid
  3. For 5xx, retry after a delay — server-side issues are usually transient
  4. Check the requested channel (CHANNEL env at build time) is one the endpoint supports
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = check_status(...) {
    let msg = e.to_string();
    if msg.contains("Server returned error") {
        // 4xx: request/auth issue — report, don't retry; 5xx: back off and retry next session
    }
}

Prevention

When it happens

Trigger: The X-Auth-Token header (build-time gitbutler_access_token secret) is rejected → 401/403; server maintenance or bug → 500; malformed channel/app_name in the request body → 400. Status appears in the {e} detail.

Common situations: Expired or missing build credentials; update service redeploying; requesting a channel that the endpoint no longer serves.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/bf05f9ed177bac21. Report an issue: GitHub.