gitbutlerapp/gitbutler · error
Failed to create runtime
Error message
Failed to create runtime: {e} What it means
This error is thrown when the Tokio async runtime cannot be constructed inside the dedicated update-check thread spawned by check_status_with_url. The function runs a current-thread Tokio runtime to perform its async HTTP update check from synchronous code; if tokio's runtime builder fails (e.g. due to resource exhaustion or a broken Tokio installation/feature set), the failure is wrapped with this message. It indicates an internal environment problem, not a network or server issue.
Solutions
- Check system resources (thread limits, ulimit -u, memory) and retry the update check after pressure subsides.
- Verify only one compatible tokio version is in the dependency graph (cargo tree -p tokio) and that features 'rt' and 'io' are enabled.
- Retry check_status; runtime creation failures are usually transient environment issues.
- If embedding this crate, consider running the update check on an already-existing async runtime instead of a fresh per-call runtime.
Example fix
// before
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| anyhow::anyhow!("Failed to create runtime: {e}"))?;
// after (call from an async context instead of building a runtime per check)
let status = tokio::task::spawn_blocking(move || perform_update_check(...)).await??; Defensive patterns
Strategy: try-catch
Try / catch
match but_update::check_status(app, &settings, &mut cache) {
Err(e) if e.to_string().contains("Failed to create runtime") => {
// environment/resource problem: log and degrade gracefully
log::warn!("update check unavailable: {e:#}");
}
result => result?,
} Prevention
- Avoid nesting this call inside heavily thread-constrained contexts; check ulimit/thread budgets.
- Keep the tokio dependency graph free of duplicate conflicting versions.
- Treat update checks as best-effort: always fall back to cached results.
When it happens
Trigger: Calling check_status or check_status_with_url when tokio::runtime::Builder::new_current_thread().enable_all().build() fails inside the spawned thread — typically from thread-local resource exhaustion, too many live runtimes, or a Tokio feature/build misconfiguration.
Common situations: System under severe thread/memory pressure when the update check runs; embedding in a process that restricts thread creation (rlimits, sandboxes, some CI containers); a Tokio dependency misconfiguration (io/timer drivers not enabled — though enable_all covers feature-gating, conflicting tokio versions can still break driver setup).
Related errors
- Failed fetch review : failed to create Tokio runtime
- Failed to create a runtime for the settled-review sweep
- failed to create tokio runtime
- GenericFailure
- assignments_error: assignments_error.clone()…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/6e9272f33441ee89.
Report an issue: GitHub.
Appendix: 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 58e5313667)