{"record":{"id":"b2dad2dbe28637f0","repo":"linebender/druid","slug":"unable-to-acquire-underlying-compositor-to-create-b2dad2","errorCode":null,"errorMessage":"unable to acquire underlying compositor to create an xdg positioner","messagePattern":"unable to acquire underlying compositor to create an xdg positioner","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"druid-shell/src/backend/wayland/surfaces/mod.rs","lineNumber":158,"sourceCode":"    }\n\n    fn create_region(&self) -> wlc::Main<WlRegion> {\n        match self.inner.upgrade() {\n            None => panic!(\"unable to acquire underlying compositor to create a region\"),\n            Some(c) => c.create_region(),\n        }\n    }\n\n    fn shared_mem(&self) -> wlc::Main<WlShm> {\n        match self.inner.upgrade() {\n            None => panic!(\"unable to acquire underlying compositor to acquire shared memory\"),\n            Some(c) => c.shared_mem(),\n        }\n    }\n\n    fn get_xdg_positioner(&self) -> wlc::Main<xdg_positioner::XdgPositioner> {\n        match self.inner.upgrade() {\n            None => panic!(\"unable to acquire underlying compositor to create an xdg positioner\"),\n            Some(c) => c.get_xdg_positioner(),\n        }\n    }\n\n    fn get_xdg_surface(&self, s: &wlc::Main<WlSurface>) -> wlc::Main<xdg_surface::XdgSurface> {\n        match self.inner.upgrade() {\n            None => panic!(\"unable to acquire underlying compositor to create an xdg surface\"),\n            Some(c) => c.get_xdg_surface(s),\n        }\n    }\n\n    fn zwlr_layershell_v1(&self) -> Option<wlc::Main<ZwlrLayerShellV1>> {\n        match self.inner.upgrade() {\n            None => {\n                tracing::warn!(\n                    \"unable to acquire underyling compositor to acquire the layershell manager\"\n                );\n                None","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/backend/wayland/surfaces/mod.rs#L140-L176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: compositor handle dropped early\nfn make_popup(surface: Surface) {\n    drop(compositor_handle); // weak ref now dead\n    surface.request_positioner(); // panics\n}\n\n// after: hold the handle for the surface's lifetime\nstruct App {\n    _compositor: CompositorHandle,\n    surface: Surface,\n}\nfn make_popup(app: &App) {\n    app.surface.request_positioner(); // weak upgrade succeeds\n}","handlingStrategy":"try-catch","validationCode":"// Rust: verify the compositor handle can still be reached before issuing positioning requests\nfn compositor_alive(surface_data: &SurfaceData) -> bool {\n    surface_data.compositor.can_upgrade()\n}","typeGuard":"fn has_live_compositor(inner: &Weak<CompositorInner>) -> bool {\n    inner.upgrade().is_some()\n}","tryCatchPattern":"// panics are not catchable normally; use std::panic::catch_unwind only at task boundaries\nlet result = std::panic::catch_unwind(AssertUnwindSafe(|| {\n    surface.request_positioner();\n}));\nif result.is_err() {\n    // compositor gone: tear down window state\n}","preventionTips":["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"],"tags":["wayland","panic","lifecycle","compositor"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0f8b1195e4e073f9597f2865299c3d18f8e4005f","analyzedAt":"2026-09-10T14:27:34.582Z","contentChangedAt":"2026-09-10T14:27:34.582Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}