niri-wm/niri · critical
no X11 support
Error message
no X11 support
What it means
Unmapped wraps a newly created window between creation and its initial xdg configure. toplevel() unwraps Window::toplevel(), which returns Some only for Wayland xdg_shell toplevels and None for X11 (Xwayland) windows — hence the message 'no X11 support'. X11 windows are not supposed to enter the unmapped map at all, so this expect firing means an X11 window reached a Wayland-only code path: an internal invariant violation (bug), and it panics the compositor.
Source
Thrown at src/window/unmapped.rs:98
impl Unmapped {
/// Wraps a newly created window that hasn't been initially configured yet.
pub fn new(window: Window) -> Self {
Self {
window,
state: InitialConfigureState::NotConfigured {
wants_fullscreen: None,
wants_maximized: false,
},
activation_token_data: None,
}
}
pub fn needs_initial_configure(&self) -> bool {
matches!(self.state, InitialConfigureState::NotConfigured { .. })
}
pub fn toplevel(&self) -> &ToplevelSurface {
self.window.toplevel().expect("no X11 support")
}
}
View on GitHub (pinned to 606284464d)
Solutions
- Update niri — invariant panics on X11 windows are bug fixes (check the issue tracker for 'no X11 support' backtraces).
- Capture the backtrace from the crash log (journalctl --user -u niri or stderr) and report it with the exact X11 app that triggered it.
- As a workaround, avoid the triggering app or run X11 apps through a translation layer (xwayland-satellite) instead of direct Xwayland mapping.
- If developing against niri sources, ensure X11 windows bypass the unmapped/initial-configure path (only xdg toplevels should be wrapped in Unmapped::new).
Example fix
// before: panics if an X11 window ever gets wrapped
pub fn toplevel(&self) -> &ToplevelSurface {
self.window.toplevel().expect("no X11 support")
}
// after: keep the invariant at construction instead — only wrap xdg toplevels
if let Some(_toplevel) = window.toplevel() {
unmapped.insert(Unmapped::new(window.clone()));
} Defensive patterns
Strategy: type-guard
Validate before calling
// Rust: only wrap windows that can receive an xdg initial configure
if window.toplevel().is_some() {
unmapped.insert(Unmapped::new(window.clone()));
} else {
debug!("skipping unmapped tracking for non-xdg window (X11)");
} Type guard
fn as_xdg_toplevel(window: &smithay::desktop::Window) -> Option<&ToplevelSurface> {
window.toplevel() // Some only for Wayland xdg_shell toplevels, None for X11 windows
} Try / catch
let toplevel = self
.window
.toplevel()
.ok_or_else(|| anyhow!("window has no xdg toplevel (X11 windows never reach the unmapped state)"))?;
// returning Err instead of expect keeps the compositor alive and the bug reportable Prevention
- Treat this panic as a niri bug: capture the backtrace and the X11 app that triggered it, then report upstream.
- Keep niri updated — X11 window-routing regressions are fixed quickly once reported.
- When hacking on niri/smithay, assert the Wayland-only invariant at Unmapped::new instead of at every toplevel() call site.
- Reproduce deterministically (same X11 app, same close/reopen sequence) before filing.
When it happens
Trigger: An Xwayland client's window being inserted into the Unmapped flow (the map keyed for new windows awaiting initial configure) — e.g. a regression in how X11 windows are routed during map/unmap, typically triggered by starting or closing an X11 app under Xwayland.
Common situations: Hitting a niri bug after an update when an X app (or one run via xwayland-satellite style paths) maps a window; race conditions around Xwayland startup at session start; building niri from a dev branch with incomplete X11 handling.
Related errors
AI-assisted analysis of niri-wm/niri@606284464d (2026-08-16).
Data as JSON: /api/errors/262ca5110ae75234.
Report an issue: GitHub.