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
- Check thread and fd limits (ulimit -n, ulimit -u) and raise them if the process is exhausted
- Look for thread leaks in the app (this runtime-per-check pattern allocates one thread each call)
- Retry the update check later — transient resource pressure clears
- 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
- Treat update-check failures as non-fatal: never block app startup on them
- Raise ulimits / fix thread leaks if this recurs — runtime build failure signals resource exhaustion
- Use the cached CheckUpdateStatus from the DB when a fresh check fails
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
- failed to create tokio runtime
- Request failed: {e}
- Server returned error: {e}
- Failed to parse response: {e}
- Update check thread panicked
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/6e9272f33441ee89.
Report an issue: GitHub.