gitbutlerapp/gitbutler · critical
Failed to create window
Error message
Failed to create window
What it means
In the Tauri setup hook, main() creates the 'main' window via gitbutler_tauri::window::create(...) and unwraps with expect("Failed to create window"). create() configures a tauri::WebviewWindowBuilder (fixed label 'main', min size, navigation guard) and returns its build() Result; that fails when the platform webview cannot be created - missing WebView2 runtime on Windows, missing webkit2gtk on Linux, no display on headless Linux - or when a window with the same label already exists.
Source
Thrown at crates/gitbutler-tauri/src/main.rs:120
let log = tauri_plugin_log::Builder::default()
.target(Target::new(TargetKind::LogDir {
file_name: Some("ui-logs".to_string()),
}))
.level(if tauri_debug_logging {
tauri_plugin_log::log::LevelFilter::Debug
} else {
tauri_plugin_log::log::LevelFilter::Error
});
let builder = tauri::Builder::default()
.setup(move |tauri_app| {
let window = gitbutler_tauri::window::create(
tauri_app.handle(),
"main",
"index.html".into(),
)
.expect("Failed to create window");
// TODO(mtsgrd): Is there a better way to disable devtools in E2E tests?
#[cfg(debug_assertions)]
if tauri_app.config().product_name != Some("GitButler Test".to_string()) {
window.open_devtools();
}
let app_handle = tauri_app.handle();
logs::init(app_handle, &app_log_dir, performance_logging, tokio_debug);
but_action::cli::auto_fix_broken_but_cli_symlink();
inherit_interactive_login_shell_environment_if_not_launched_from_terminal();
migrate_projects().ok();
tracing::info!(
"system git executable for fetch/push: {git:?}",
git = gix::path::env::exe_invocation(),View on GitHub (pinned to caf1f223d3)
Solutions
- Install the platform webview: webkit2gtk 4.1 packages on Linux, WebView2 Runtime on Windows
- Run the app inside a graphical session: set DISPLAY/WAYLAND_DISPLAY, or use xvfb-run for automated runs
- Ensure the window label 'main' is created exactly once and not already registered
- Propagate the tauri::Error with ? - the setup closure already returns Result (see exampleFix)
Example fix
// before
let window = gitbutler_tauri::window::create(tauri_app.handle(), "main", "index.html".into())
.expect("Failed to create window");
// after - surfaces the underlying tauri::Error through setup's Result
let window = gitbutler_tauri::window::create(tauri_app.handle(), "main", "index.html".into())?; Defensive patterns
Strategy: try-catch
Validate before calling
// Headless guard for Linux launches
#[cfg(target_os = "linux")]
fn display_available() -> bool {
std::env::var_os("DISPLAY").is_some() || std::env::var_os("WAYLAND_DISPLAY").is_some()
}
// xvfb-run ./GitButler # gives CI a virtual display Try / catch
// The setup closure returns Result - propagate instead of expect let window = gitbutler_tauri::window::create(tauri_app.handle(), "main", "index.html".into())?;
Prevention
- Ship webview prerequisites with installers: webkit2gtk on Linux, WebView2 bootstrapper on Windows
- Never launch the GUI app without a display; use xvfb-run in automation
- Create each window label exactly once per app instance
When it happens
Trigger: Launching the desktop app on a machine without the platform webview: Linux without webkit2gtk installed or without DISPLAY/WAYLAND_DISPLAY (SSH sessions, containers), Windows lacking the WebView2 runtime, or code that creates a second window with the label 'main'.
Common situations: Running the packaged app over SSH or in CI/containers, minimal Linux installs, locked-down Windows Server images without WebView2, and local dev after a system upgrade broke webkit2gtk.
Related errors
- failed to create logs dir
- initializing rolling file appender failed
- product name not set
- missing config dir
- failed to create config dir
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/c34fe476092855b4.
Report an issue: GitHub.