gitbutlerapp/gitbutler · warning · anyhow::Error

Update check thread panicked

Error message

Update check thread panicked

What it means

The dedicated thread spawned for the update check panicked (or was forcibly terminated), so join() returned Err and the payload was discarded. The real panic message went to stderr; this error only says the join failed. Inside the thread, panics can come from the runtime build, the request, or response handling.

Source

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

            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();
        let (suppressed_at, suppress_duration_hours) = existing
            .and_then(|cached| cached.suppressed_at.zip(cached.suppress_duration_hours))
            .and_then(|(suppressed_at, duration_hours)| {
                let suppress_until = suppressed_at + chrono::Duration::hours(duration_hours as i64);
                if now > suppress_until {
                    None
                } else {
                    Some((suppressed_at, duration_hours))
                }
            })
            .unzip();

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Check stderr/logs for the actual panic backtrace that accompanied this error
  2. Update check is non-critical: catch this error and continue with cached/no update info
  3. If reproducible, run under a debugger or RUST_BACKTRACE=full to capture the panicking frame
  4. Upgrade but-update — panics in this path get fixed like any bug
Defensive patterns

Strategy: fallback

Try / catch

if let Err(e) = check_status(...) {
    if e.to_string().contains("thread panicked") {
        // capture stderr/backtrace in telemetry; fall back to cached status
    }
}

Prevention

When it happens

Trigger: Any panic inside the spawned closure — e.g. a reqwest/tokio invariant, an unwrap in the caching code after join, or the thread aborted due to stack overflow/OOM kill.

Common situations: Rare; typically surfaces with a concurrent stderr panic backtrace. Aborts from OOM also manifest this way.

Related errors


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