linebender/druid · critical
unable to acquire underlying compositor to create an xdg…
Error message
unable to acquire underlying compositor to create an xdg surface
What it means
Same weak-reference pattern as the positioner variant: get_xdg_surface upgrades a weak compositor reference to fetch the xdg_surface object for a WlSurface. If the strong compositor handle was already dropped, upgrade fails and the library panics. It means a Wayland xdg surface (the protocol object backing a toplevel) cannot be created because the compositor is unreachable.
Solutions
- Keep the CompositorHandle alive until every surface creation completes; store it in your application state alongside the surfaces.
- Create windows before any teardown of the compositor; avoid creating windows from tasks that can outlive the main handle.
- Verify you are not using a Surface whose originating compositor has disconnected (e.g. after compositor crash/restart).
- Restructure so surface creation happens synchronously in the same scope where the compositor handle exists.
Example fix
// before: surface outlives the compositor handle
let surface;
{
let compositor = connect()?;
surface = Surface::new(&compositor, handler, size);
} // handle dropped, later new/replace panics
// after: own the handle with the surface
struct Window {
_compositor: CompositorHandle,
surface: Surface,
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check compositor reachability before creating windows
if !compositor.can_upgrade() {
eprintln!("compositor handle dead; cannot create window");
return;
} Type guard
fn can_create_surface(inner: &Weak<CompositorInner>) -> bool {
inner.upgrade().is_some()
} Try / catch
std::panic::catch_unwind(AssertUnwindSafe(|| Surface::new(&handle, handler, size)))
.map_err(|_| WindowError::CompositorGone) Prevention
- Create windows in the same scope/lifetime as the compositor handle
- Store the CompositorHandle in long-lived application state
- Never spawn window-creation tasks that can outlive the main handle
- Treat compositor disconnect as fatal for all pending window creations
When it happens
Trigger: Creating a new window/surface (via Surface::new or layer-shell paths) when the compositor handle backing the weak reference has been dropped, so the upgrade inside get_xdg_surface returns None.
Common situations: Window creation during or after Wayland compositor teardown; storing a Surface without keeping the CompositorHandle/WindowHandle alive; delayed window creation (e.g. spawning a window on a background task) after the initiating handle was dropped.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- unable to acquire underlying compositor to create an xdg…
- unable to create surface
- get_idle_handle invoked on a dead surface
- unexpected wayland event
- unrecognised key event
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/fad274097c08f7e5.
Report an issue: GitHub.
Appendix: source
Thrown at druid-shell/src/backend/wayland/surfaces/mod.rs:165
}
fn shared_mem(&self) -> wlc::Main<WlShm> {
match self.inner.upgrade() {
None => panic!("unable to acquire underlying compositor to acquire shared memory"),
Some(c) => c.shared_mem(),
}
}
fn get_xdg_positioner(&self) -> wlc::Main<xdg_positioner::XdgPositioner> {
match self.inner.upgrade() {
None => panic!("unable to acquire underlying compositor to create an xdg positioner"),
Some(c) => c.get_xdg_positioner(),
}
}
fn get_xdg_surface(&self, s: &wlc::Main<WlSurface>) -> wlc::Main<xdg_surface::XdgSurface> {
match self.inner.upgrade() {
None => panic!("unable to acquire underlying compositor to create an xdg surface"),
Some(c) => c.get_xdg_surface(s),
}
}
fn zwlr_layershell_v1(&self) -> Option<wlc::Main<ZwlrLayerShellV1>> {
match self.inner.upgrade() {
None => {
tracing::warn!(
"unable to acquire underyling compositor to acquire the layershell manager"
);
None
}
Some(c) => c.zwlr_layershell_v1(),
}
}
}
View on GitHub (pinned to 0f8b1195e4)