iced-rs/iced · critical

Create window

Error message

Create window

What it means

This panic fires when EventLoop::create_window(window_attributes) returns an OsError inside iced's window-opening control (winit/src/lib.rs:341-343). The platform rejected the window creation: no usable graphics/EGL/GLX connection (missing Mesa/libEGL, broken or absent GPU driver), an invalid combination of window attributes (size/position/monitor), or — on the web target, visible in the surrounding code that does `window_attributes.with_canvas(self.canvas.take())` — no HTML canvas for iced to adopt. Because iced unwraps with .expect("Create window"), the app panics while opening the first window or any later window opened at runtime via iced::window::open.

Source

Thrown at winit/src/lib.rs:343

                                    window_attributes.with_canvas(self.canvas.take())
                                };

                                log::info!(
                                    "Window attributes for id `{id:#?}`: {window_attributes:#?}"
                                );

                                // On macOS, the `position` in `WindowAttributes` represents the "inner"
                                // position of the window; while on other platforms it's the "outer" position.
                                // We fix the inconsistency on macOS by positioning the window after creation.
                                #[cfg(target_os = "macos")]
                                let mut window_attributes = window_attributes;

                                #[cfg(target_os = "macos")]
                                let position = window_attributes.position.take();

                                let window = event_loop
                                    .create_window(window_attributes)
                                    .expect("Create window");

                                #[cfg(target_os = "macos")]
                                if let Some(position) = position {
                                    window.set_outer_position(position);
                                }

                                #[cfg(target_arch = "wasm32")]
                                {
                                    use winit::platform::web::WindowExtWebSys;

                                    let canvas = window.canvas().expect("Get window canvas");

                                    let _ = canvas.set_attribute(
                                        "style",
                                        "display: block; width: 100%; height: 100%",
                                    );

                                    let window = web_sys::window().unwrap();

View on GitHub (pinned to 2cffa99b39)

Solutions

  1. Verify a working GL/EGL stack first: run `glxinfo -B` (or `eglinfo`) and confirm it reports a vendor; install Mesa/libEGL packages (libgl1-mesa-dri, libegl1) and matching GPU drivers.
  2. Where there is no real GPU (VM, container, CI), force software rendering: LIBGL_ALWAYS_SOFTWARE=1 and/or WGPU_BACKEND=gl, or install a software EGL implementation (lavapipe/swiftshader).
  3. On wasm, guarantee the canvas exists before iced boots: put the <canvas> in the static HTML, load the wasm module at the end of <body> or on DOMContentLoaded, and match its id to the window settings' platform_specific.target.
  4. When opening windows at runtime, re-query event_loop.primary_monitor()/available_monitors() at call time (as this code does) instead of caching monitor handles, and clamp requested size/position to the current monitor bounds.
  5. Capture the real cause: iced logs the full window_attributes at info level immediately before the call, so run with RUST_LOG=iced_winit=info (plus RUST_BACKTRACE=1) and read the underlying OsError from the panic output.

Example fix

<!-- before (web): iced boots before any canvas exists -->
<head><script type="module" src="pkg/app.js"></script></head>
<body></body>

<!-- after: canvas present in static HTML, id matches target -->
<body>
  <canvas id="iced-canvas"></canvas>
  <script type="module" src="pkg/app.js"></script>
</body>

// main.rs — point iced at that canvas
let settings = iced::window::Settings {
    platform_specific: PlatformSpecific {
        target: Some("iced-canvas".into()),
        ..Default::default()
    },
    ..Default::default()
};
iced::application("App", Update::new, View::new)
    .window(settings)
    .run()
Defensive patterns

Strategy: validation

Validate before calling

// Web: confirm the canvas exists before handing control to iced
fn canvas_ready(target: &str) -> bool {
    web_sys::window()
        .and_then(|w| w.document())
        .and_then(|d| d.query_selector(&format!("#{target}")))
        .unwrap_or(Ok(None))
        .is_ok_and(|el| el.is_some())
}

// Desktop: verify a GL/EGL path exists before first launch
//   glxinfo -B   ||   eglinfo
# and for GPU-less environments, launch with:
#   LIBGL_ALWAYS_SOFTWARE=1 WGPU_BACKEND=gl ./app

Prevention

When it happens

Trigger: Launching on a machine without working EGL/GLX (containers or minimal Linux images without Mesa, libEGL missing, NVIDIA driver mismatch); remote sessions (VNC/RDP/ssh -X) without 3D acceleration so GLX/EGL initialization fails; on wasm32, starting iced before the DOM contains a <canvas>, so canvas.take() yields None; opening runtime windows with attributes built around a monitor that has since been unplugged; window attributes the windowing system rejects (e.g. zero size).

Common situations: Desktop apps deployed to minimal Linux images or sandboxes without GPU libraries; web builds where the canvas element is missing, created late by JS, or its id doesn't match settings.platform_specific.target; multi-window apps on laptops docking/undocking external monitors; driver updates that leave wgpu/winit unable to create a surface; CI smoke tests of the GUI without a virtual display and software GL.

Related errors


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/71b4e58a15d69076. Report an issue: GitHub.