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

  1. Keep the CompositorHandle (or the WindowHandle) alive for as long as the surface can issue positioning requests; audit drop order in your app.
  2. Ensure the window/surface is fully closed and its handler detached before dropping the compositor handle.
  3. Check for refactoring that wrapped Surface/Window in a shorter-lived scope than intended; use Arc/Rc to extend the handle's lifetime.
  4. 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

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


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"
                );
                None

View on GitHub (pinned to 0f8b1195e4)