{"record":{"id":"5283c0b3f9fe7c8c","repo":"OpenCut-app/OpenCut","slug":"failed-to-open-the-main-window","errorCode":null,"errorMessage":"failed to open the main window","messagePattern":"failed to open the main window","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"apps/desktop/src/main.rs","lineNumber":56,"sourceCode":"                titlebar: Some(TitlebarOptions {\n                    title: Some(SharedString::from(\"OpenCut\")),\n                    ..Default::default()\n                }),\n                window_bounds: Some(WindowBounds::Maximized(bounds)),\n                ..Default::default()\n            },\n            |window, cx| {\n                cx.new(|cx| {\n                    cx.observe_window_appearance(window, |_, window, _| {\n                        window.refresh();\n                    })\n                    .detach();\n\n                    Shell::new(cx)\n                })\n            },\n        )\n        .expect(\"failed to open the main window\");\n    });\n}\n","sourceCodeStart":38,"sourceCodeEnd":59,"githubUrl":"https://github.com/OpenCut-app/OpenCut/blob/400f097becba5db0fbc305d5a65348cb81c20356/apps/desktop/src/main.rs#L38-L59","documentation":"This is a Rust panic raised by .expect(\"failed to open the main window\") on the Result returned by GPUI 0.2.2's App::open_window (apps/desktop/src/main.rs:36-56). open_window creates the OS-level window and initializes a GPU-backed compositor surface for it; the returned Result is Err only when that platform/graphics initialization fails, so the panic message is the app author's own string, not a GPUI error text. The underlying cause is whatever the platform window+graphics backend reported (no display server, an incompatible Wayland compositor, a GPU/Vulkan/GL init failure, or a permission error such as running as root on Wayland). Because the main window is the application's only entry surface, this panic aborts the process at startup.","triggerScenarios":"Running the binary where App::open_window cannot obtain a usable window: (1) on Linux with neither DISPLAY nor WAYLAND_DISPLAY set, e.g. a plain SSH session or a systemd service/cron job with no graphical session; (2) on a Wayland compositor whose xdg_wm_base protocol is older than v2 — exactly the WSLg case the main.rs:23-31 block tries to neutralize, which still fails if the guard does not fire (e.g. is_wsl false, or only one of the two env vars set, or the unsafe removal racing with GPUI's own env read); (3) a GPU/graphics backend init failure under GPUI's Blade renderer (missing Vulkan loader, broken MESA/DRI, no suitable GPU device); (4) running the binary as root on Wayland, where most compositors refuse the connection; (5) Windows/macOS graphics-API init failure (no Metal device, locked D3D context). In every case open_window returns Err and .expect() turns it into this panic.","commonSituations":"Developers hit this most often when launching the desktop binary outside a real GUI session: over SSH without X11/Wayland forwarding, from a CI container with no display, as a systemd/launchd service, or inside a Docker/Podman image that did not install libwayland/libxkbcommon/Vulkan/OpenGL drivers. The second most common context is a version change — bumping GPUI past a point where it tightened Wayland protocol requirements (the code's own comment ties this to GPUI 0.2.2 vs WSLg's xdg_wm_base v1), or moving a binary built against a newer graphics stack onto an older host. A third context is the WSL guard at lines 23-31 silently not applying (DISPLAY and WAYLAND_DISPLAY not both set, or osrelease detection failing in an unpacked WSL rootfs), leaving the broken Wayland path active. The panic string itself carries no diagnostic, so teams often misread it as a logic bug in Shell::new rather than a window-creation failure.","solutions":["Run the binary inside a real graphical session: on Linux export DISPLAY=:0 for X11 or log into a Wayland session, on Windows/macOS just launch from the desktop; over SSH use ssh -X/-Y or a Wayland portal.","If on WSL and the panic still occurs, confirm the guard at main.rs:23-31 is firing: check /proc/sys/kernel/osrelease contains 'microsoft', that both DISPLAY and WAYLAND_DISPLAY are set before launch (the guard needs both), and that WAYLAND_DISPLAY is unset afterwards; if only one is set, the guard is skipped and you must `unset WAYLAND_DISPLAY` (or remove it from the environment) manually so GPUI falls back to X11/XWayland.","Surface the real cause instead of the opaque string: replace .expect(\"...\") with a match on the Result and print or log the inner GPUI error (e.g. `match cx.open_window(...) { Ok(_) => {}, Err(e) => { eprintln!(\"open_window failed: {e:?}\"); std::process::exit(1); } }`) so the underlying graphics/protocol error is visible.","For headless or CI execution where no real display exists, run under a virtual framebuffer: `xvfb-run -a -s \"-screen 0 1280x800x24\" ./opencut-desktop` or set up wlroots/swcweston as a nested Wayland compositor so GPUI has a windowing system to bind to.","Install the platform graphics dependencies GPUI's renderer links against: on Linux add libwayland, libxkbcommon, vulkan-loader, mesa-dri/GPU drivers and the xdg_wm_base-providing compositor; verify with `vulkaninfo` / `glxinfo | grep 'OpenGL renderer'`; on macOS confirm a Metal device exists, on Windows confirm D3D11+ is available.","Do not run the GUI binary as root/sudo under Wayland — compositors reject root clients; run as the session user, or switch the session to X11 where root is tolerated.","Pin or align GPUI to a version compatible with the target compositor; if the host cannot be upgraded past xdg_wm_base v1 (older WSLg), keep the WAYLAND_DISPLAY-stripping workaround and ensure it runs before any GPUI thread spawns, as the comment at main.rs:24-27 requires."],"exampleFix":"// before (apps/desktop/src/main.rs:36-56) — opaque panic, no diagnostic:\n        cx.open_window(\n            WindowOptions { /* ... */ },\n            |window, cx| {\n                cx.new(|cx| { /* ... */ Shell::new(cx) })\n            },\n        )\n        .expect(\"failed to open the main window\");\n\n// after — surface the real platform/graphics error and exit cleanly:\n        if let Err(e) = cx.open_window(\n            WindowOptions { /* ... */ },\n            |window, cx| {\n                cx.new(|cx| {\n                    cx.observe_window_appearance(window, |_, window, _| window.refresh())\n                        .detach();\n                    Shell::new(cx)\n                })\n            },\n        ) {\n            eprintln!(\n                \"failed to open the main window: {e:?}\\n\\\n                 hint: ensure a display server is available (DISPLAY or WAYLAND_DISPLAY), \\n\\\n                 GPU/Vulkan drivers are installed, and you are not running headless or as root on Wayland.\"\n            );\n            cx.quit();\n        }","handlingStrategy":"try-catch","validationCode":"// Run BEFORE Application::run so you fail fast with a clear message\n// instead of letting GPUI panic deep in window creation.\n#[cfg(target_os = \"linux\")]\nfn ensure_display_available() {\n    let has_x11 = std::env::var_os(\"DISPLAY\").is_some_and(|d| !d.is_empty());\n    let has_wayland = std::env::var_os(\"WAYLAND_DISPLAY\").is_some_and(|d| !d.is_empty());\n    if !has_x11 && !has_wayland {\n        eprintln!(\"no display server found: set DISPLAY (X11) or WAYLAND_DISPLAY, \\n                   use ssh -X/-Y, or run under xvfb-run.\");\n        std::process::exit(1);\n    }\n    if std::id::equals(0) && has_wayland && !has_x11 {\n        eprintln!(\"running as root under Wayland is rejected by most compositors; \\n                   run as the session user or switch to an X11 session.\");\n        std::process::exit(1);\n    }\n}\n\nfn main() {\n    #[cfg(target_os = \"linux\")] ensure_display_available();\n    Application::new().run(|cx: &mut App| { /* ... open_window ... */ });\n}","typeGuard":"// GPUI's open_window returns Result<Window, gpui::Errno> (platform-specific Error).\n// There is no narrower type to guard on, so narrow by case on the Result itself:\nfn try_open_main_window(cx: &mut gpui::App, opts: gpui::WindowOptions) -> bool {\n    match cx.open_window(opts, |window, cx| {\n        cx.new(|cx| { /* build Shell::new(cx) */ shell::Shell::new(cx) })\n    }) {\n        Ok(_) => true,\n        Err(err) => {\n            eprintln!(\"open_window rejected: {err:?}\");\n            false\n        }\n    }\n}","tryCatchPattern":"// Inside Application::run — replace .expect() with explicit error handling.\n// GPUI does not throw; it returns Result, so the Rust idiom is match / if let Err.\nApplication::new().run(|cx: &mut App| {\n    let result = cx.open_window(WindowOptions { /* ... */ }, |window, cx| {\n        cx.new(|cx| {\n            cx.observe_window_appearance(window, |_, w, _| w.refresh()).detach();\n            Shell::new(cx)\n        })\n    });\n    if let Err(err) = result {\n        tracing::error!(?err, \"failed to open the main window\");\n        eprintln!(\"failed to open the main window: {err:?}\");\n        // Stop the app cleanly instead of panicking.\n        cx.quit();\n    }\n});","preventionTips":["Never launch a GPUI desktop binary in a session with no display server; gate startup with a DISPLAY/WAYLAND_DISPLAY check on Linux and exit with a clear message before calling Application::run.","On WSL, keep the WAYLAND_DISPLAY-stripping guard at the very top of main and assert it actually ran (log when it fires) so a guard that silently fails to match is caught in CI rather than in production.","Treat .expect() on open_window as a defect: replace it with match/if-let-Err that prints the inner error — the opaque string hides graphics/protocol causes that are trivial to fix once seen.","Run desktop smoke tests under xvfb-run (or a nested Weston) in CI so a regression in window creation is caught on a headless runner with a synthetic display, mirroring real Linux failure modes.","Document the host graphics requirements (libwayland, libxkbcommon, vulkan-loader, GPU drivers; Metal device on macOS; D3D11+ on Windows) and assert them in setup scripts so a missing dependency is reported before launch, not as a panic.","Do not run the GUI binary as root/sudo under Wayland; either run as the session user or provide an X11 session where root clients are accepted.","Pin GPUI to a version validated against the oldest compositor you support (xdg_wm_base protocol version), and re-run the smoke test whenever GPUI is bumped."],"tags":["rust","gpui","window-creation","wayland","wsl","gpu","linux","headless","expect-panic"],"backgroundTag":null,"analyzedSha":"400f097becba5db0fbc305d5a65348cb81c20356","analyzedAt":"2026-08-12T10:02:41.428Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}