gitbutlerapp/gitbutler · warning · anyhow::Error

Failed to create runtime: {e}

Error message

Failed to create runtime: {e}

What it means

The update checker spawns a thread and builds a single-threaded tokio runtime on it (Builder::new_current_thread().enable_all().build()); the build failed. This is an environment-level failure — typically thread/resource exhaustion or an OS restriction — not a network problem.

Source

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

        arch: arch.to_string(),
        version: version.to_string(),
        app_name: app_name.to_string(),
        posthog_id: app_settings.telemetry.distinct_id_if_enabled(),
        install: install(),
    };

    let client = reqwest::Client::builder()
        .default_headers(headers)
        .timeout(REQUEST_TIMEOUT)
        .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)
        })

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Check thread and fd limits (ulimit -n, ulimit -u) and raise them if the process is exhausted
  2. Look for thread leaks in the app (this runtime-per-check pattern allocates one thread each call)
  3. Retry the update check later — transient resource pressure clears
  4. In sandboxes, allow thread/epoll creation for the app process
Defensive patterns

Strategy: fallback

Validate before calling

// before spawning, sanity-check resource headroom
// (cheap heuristic; real cause shows in OS errors)
if std::thread::available_parallelism().is_err() { /* heavily restricted env: skip update check */ }

Try / catch

if let Err(e) = but_update::check::check_status(...) {
    if e.to_string().contains("Failed to create runtime") {
        // environment issue, not an update problem: log once and skip
    }
}

Prevention

When it happens

Trigger: check_status running on a machine at the process limit for threads or file descriptors, in a sandbox that forbids thread/epoll creation, or under memory pressure where the runtime allocation fails.

Common situations: Long-running desktop app with a thread leak eventually cannot spawn runtimes; restricted containers/CI sandboxes; very low ulimits.

Related errors


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