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
- 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.
- 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).
- 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.
- 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.
- 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
- Smoke-test release binaries in a clean container/VM with software GL forced, so missing-driver environments surface gracefully instead of panicking.
- On the web, always ship the <canvas> in static HTML and load the wasm module after the DOM; never rely on JS creating the canvas later.
- When opening windows at runtime, re-query monitors at call time and clamp position/size to the monitor's current bounds.
- Develop with RUST_LOG=iced_winit=info — it prints the exact WindowAttributes before every create_window call, which is the first thing a bug report will need.
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.