linebender/druid · critical
unable to acquire underlying compositor to create an xdg…
Error message
unable to acquire underlying compositor to create an xdg positioner
What it means
druid-shell's Wayland surface helper holds only a weak reference to the compositor handle. When get_xdg_positioner is called after the strong compositor handle has been dropped, the weak upgrade fails and the library panics rather than returning a Result. It means the window's backing compositor is gone, so an xdg positioner cannot be created for positioning/popup requests.
Solutions
- Keep the CompositorHandle (or the WindowHandle) alive for as long as the surface can issue positioning requests; audit drop order in your app.
- Ensure the window/surface is fully closed and its handler detached before dropping the compositor handle.
- Check for refactoring that wrapped Surface/Window in a shorter-lived scope than intended; use Arc/Rc to extend the handle's lifetime.
- If this fires during app shutdown, guard against issuing move/resize/popup requests after the compositor disconnect.
Example fix
// before: compositor handle dropped early
fn make_popup(surface: Surface) {
drop(compositor_handle); // weak ref now dead
surface.request_positioner(); // panics
}
// after: hold the handle for the surface's lifetime
struct App {
_compositor: CompositorHandle,
surface: Surface,
}
fn make_popup(app: &App) {
app.surface.request_positioner(); // weak upgrade succeeds
} Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: verify the compositor handle can still be reached before issuing positioning requests
fn compositor_alive(surface_data: &SurfaceData) -> bool {
surface_data.compositor.can_upgrade()
} Type guard
fn has_live_compositor(inner: &Weak<CompositorInner>) -> bool {
inner.upgrade().is_some()
} Try / catch
// panics are not catchable normally; use std::panic::catch_unwind only at task boundaries
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
surface.request_positioner();
}));
if result.is_err() {
// compositor gone: tear down window state
} Prevention
- Own the CompositorHandle in the same struct that owns the Surface so drop order is guaranteed
- Never drop the compositor handle before all windows are closed
- Add a debug assertion using can_upgrade() before issuing Wayland requests
- Review handle cloning vs moving when refactoring window management code
When it happens
Trigger: Calling code that triggers a window move/resize or popup positioning (e.g. dragging via the title bar, context menus) after the CompositorHandle backing this surface's weak reference has been dropped, so inner.upgrade() returns None.
Common situations: Happens during Wayland teardown or handle-lifetime mistakes: the compositor object was dropped while a surface still tries to open a popup or reposition a window; often seen when application code drops its compositor/window handles early or during shutdown races.
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/b2dad2dbe28637f0.
Report an issue: GitHub.
Appendix: source
Thrown at druid-shell/src/backend/wayland/surfaces/mod.rs:158
}
fn create_region(&self) -> wlc::Main<WlRegion> {
match self.inner.upgrade() {
None => panic!("unable to acquire underlying compositor to create a region"),
Some(c) => c.create_region(),
}
}
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"
);
NoneView on GitHub (pinned to 0f8b1195e4)